Skip to content

Commit feb2dcb

Browse files
author
Clark Perkins
committed
Got autocomplete working in the shell\!
1 parent eea4bd2 commit feb2dcb

File tree

2 files changed

+147
-55
lines changed

2 files changed

+147
-55
lines changed

stackdio/cli/__init__.py

Lines changed: 14 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from requests import ConnectionError
1313

1414
from stackdio.cli import mixins
15+
from stackdio.cli.shell import get_shell
1516
from stackdio.client import StackdIO
1617
from stackdio.client.version import __version__
1718

@@ -42,64 +43,22 @@ def get_client():
4243
)
4344

4445

45-
def get_invoke(ctx, command):
46-
def invoke(self, arg):
47-
return ctx.invoke(command)
48-
return invoke
46+
class StackdioObj(object):
4947

50-
51-
def get_help(command):
52-
def help(self):
53-
click.echo(command.help)
54-
return help
55-
56-
57-
def get_shell(ctx):
58-
59-
# Make it a new-style class so we can use super!
60-
class StackdioShell(Cmd, object):
61-
62-
def __init__(self):
63-
super(StackdioShell, self).__init__()
64-
65-
prompt = 'stackdio > '
66-
67-
def emptyline(self):
68-
pass
69-
70-
def do_quit(self, arg):
71-
return True
72-
73-
def do_exit(self, arg):
74-
return True
75-
76-
def do_EOF(self, arg):
77-
return True
78-
79-
def get_names(self):
80-
ret = super(StackdioShell, self).get_names()
81-
# We don't want to display
82-
ret.remove('do_EOF')
83-
return ret
84-
85-
for name, command in ctx.command.commands.items():
86-
setattr(StackdioShell, 'do_%s' % name.replace('-', '_'), get_invoke(ctx, command))
87-
88-
if command.help is not None:
89-
setattr(StackdioShell, 'help_%s' % name.replace('-', '_'), get_help(command))
90-
91-
return StackdioShell()
48+
def __init__(self, ctx):
49+
super(StackdioObj, self).__init__()
50+
self.shell = get_shell(ctx)
51+
self.client = get_client()
9252

9353

9454
@click.group(context_settings=CONTEXT_SETTINGS, invoke_without_command=True)
9555
@click.version_option(__version__, '-v', '--version')
9656
@click.pass_context
9757
def stackdio(ctx):
98-
ctx.client = get_client()
58+
ctx.obj = StackdioObj(ctx)
9959

10060
if ctx.invoked_subcommand is None:
101-
shell = get_shell(ctx)
102-
shell.cmdloop()
61+
ctx.obj.shell.cmdloop()
10362

10463

10564
@stackdio.group()
@@ -131,7 +90,7 @@ def server_version():
13190
click.echo('stackdio-server, version {0}'.format(client.get_version()))
13291

13392

134-
class StackdioShell(mixins.bootstrap.BootstrapMixin, mixins.stacks.StackMixin,
93+
class StackdioShell(Cmd, mixins.bootstrap.BootstrapMixin, mixins.stacks.StackMixin,
13594
mixins.formulas.FormulaMixin, mixins.blueprints.BlueprintMixin):
13695

13796
CFG_DIR = os.path.expanduser("~/.stackdio-cli/")
@@ -146,11 +105,11 @@ class StackdioShell(mixins.bootstrap.BootstrapMixin, mixins.stacks.StackMixin,
146105
"help", "exit", "quit",
147106
]
148107

149-
# Cmd.intro = """
150-
# ######################################################################
151-
# s t a c k d . i o
152-
# ######################################################################
153-
# """
108+
intro = """
109+
######################################################################
110+
s t a c k d . i o
111+
######################################################################
112+
"""
154113

155114
def __init__(self):
156115
mixins.bootstrap.BootstrapMixin.__init__(self)

stackdio/cli/shell.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# -*- coding: utf-8 -*-
2+
3+
# Copyright 2014, Digital Reasoning
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
import os
19+
from cmd import Cmd
20+
21+
import click
22+
23+
from stackdio.client.version import __version__
24+
25+
26+
try:
27+
import readline
28+
except ImportError:
29+
readline = None
30+
31+
32+
HIST_FILE = os.path.join(os.path.expanduser('~'), '.stackdio-cli', 'history')
33+
34+
35+
def get_invoke(ctx, command):
36+
def invoke(self, arg):
37+
return ctx.invoke(command)
38+
return invoke
39+
40+
41+
def get_help(command):
42+
def help(self):
43+
click.echo(command.help)
44+
return help
45+
46+
47+
def get_shell(ctx):
48+
49+
# Make it a new-style class so we can use super
50+
class StackdioShell(Cmd, object):
51+
52+
def __init__(self):
53+
super(StackdioShell, self).__init__()
54+
self.old_completer = None
55+
56+
def preloop(self):
57+
# read our history
58+
if readline:
59+
try:
60+
readline.read_history_file(HIST_FILE)
61+
except IOError:
62+
pass
63+
64+
def postloop(self):
65+
# Write our history
66+
if readline:
67+
readline.write_history_file(HIST_FILE)
68+
69+
prompt = 'stackdio > '
70+
intro = 'stackdio shell v{0}'.format(__version__)
71+
72+
# We need to override this to fix readline
73+
def cmdloop(self, intro=None):
74+
self.preloop()
75+
if self.use_rawinput and self.completekey and readline:
76+
self.old_completer = readline.get_completer()
77+
readline.set_completer(self.complete)
78+
if 'libedit' in readline.__doc__:
79+
# For mac
80+
readline.parse_and_bind('bind ^I rl_complete')
81+
else:
82+
# for other platforms
83+
readline.parse_and_bind(self.completekey + ': complete')
84+
try:
85+
if intro is not None:
86+
self.intro = intro
87+
if self.intro:
88+
self.stdout.write(str(self.intro)+"\n")
89+
stop = None
90+
while not stop:
91+
if self.cmdqueue:
92+
line = self.cmdqueue.pop(0)
93+
else:
94+
if self.use_rawinput:
95+
try:
96+
line = raw_input(self.prompt)
97+
except EOFError:
98+
# We just want to quit here
99+
self.stdout.write('\n')
100+
break
101+
else:
102+
self.stdout.write(self.prompt)
103+
self.stdout.flush()
104+
line = self.stdin.readline()
105+
if not len(line):
106+
line = 'EOF'
107+
else:
108+
line = line.rstrip('\r\n')
109+
line = self.precmd(line)
110+
stop = self.onecmd(line)
111+
stop = self.postcmd(stop, line)
112+
113+
finally:
114+
self.postloop()
115+
if self.use_rawinput and self.completekey and readline:
116+
readline.set_completer(self.old_completer)
117+
118+
def emptyline(self):
119+
pass
120+
121+
def do_quit(self, arg):
122+
return True
123+
124+
def do_exit(self, arg):
125+
return True
126+
127+
for name, command in ctx.command.commands.items():
128+
setattr(StackdioShell, 'do_%s' % name.replace('-', '_'), get_invoke(ctx, command))
129+
130+
if command.help is not None:
131+
setattr(StackdioShell, 'help_%s' % name.replace('-', '_'), get_help(command))
132+
133+
return StackdioShell()

0 commit comments

Comments
 (0)