4
4
5
5
"""
6
6
from __future__ import unicode_literals
7
+ import os
7
8
import tempfile
8
9
import subprocess
9
10
import logging
11
+ import sys
10
12
11
13
from prompt_toolkit .document import Document
12
14
from prompt_toolkit .shortcuts import create_eventloop
25
27
from awsshell .style import StyleFactory
26
28
from awsshell .toolbar import Toolbar
27
29
from awsshell .utils import build_config_file_path
30
+ from awsshell import compat
28
31
29
32
30
33
LOG = logging .getLogger (__name__ )
@@ -43,6 +46,76 @@ class InputInterrupt(Exception):
43
46
pass
44
47
45
48
49
+ class EditHandler (object ):
50
+ def __init__ (self , popen_cls = None , env = None ):
51
+ if popen_cls is None :
52
+ popen_cls = subprocess .Popen
53
+ self ._popen_cls = popen_cls
54
+ if env is None :
55
+ env = os .environ
56
+ self ._env = env
57
+
58
+ def _get_editor_command (self ):
59
+ if 'EDITOR' in self ._env :
60
+ return self ._env ['EDITOR' ]
61
+ else :
62
+ return compat .default_editor ()
63
+
64
+ def run (self , command , application ):
65
+ """Open application's history buffer in an editor.
66
+
67
+ :type command: list
68
+ :param command: The dot command as a list split
69
+ on whitespace, e.g ``['.foo', 'arg1', 'arg2']``
70
+
71
+ :type application: AWSShell
72
+ :param application: The application object.
73
+
74
+ """
75
+ all_commands = '\n ' .join (
76
+ ['aws ' + h for h in list (application .history )
77
+ if not h .startswith (('.' , '!' ))])
78
+ with tempfile .NamedTemporaryFile ('w' ) as f :
79
+ f .write (all_commands )
80
+ f .flush ()
81
+ editor = self ._get_editor_command ()
82
+ p = self ._popen_cls ([editor , f .name ])
83
+ p .communicate ()
84
+
85
+
86
+ class DotCommandHandler (object ):
87
+ HANDLER_CLASSES = {
88
+ 'edit' : EditHandler ,
89
+ }
90
+
91
+ def __init__ (self , output = sys .stdout , err = sys .stderr ):
92
+ self ._output = output
93
+ self ._err = err
94
+
95
+ def handle_cmd (self , command , application ):
96
+ """Handles running a given dot command from a user.
97
+
98
+ :type command: str
99
+ :param command: The full dot command string, e.g. ``.edit``,
100
+ of ``.profile prod``.
101
+
102
+ :type application: AWSShell
103
+ :param application: The application object.
104
+
105
+ """
106
+ parts = command .split ()
107
+ cmd_name = parts [0 ][1 :]
108
+ if cmd_name not in self .HANDLER_CLASSES :
109
+ self ._unknown_cmd (parts , application )
110
+ else :
111
+ # Note we expect the class to support no-arg
112
+ # instantiation.
113
+ self .HANDLER_CLASSES [cmd_name ]().run (parts , application )
114
+
115
+ def _unknown_cmd (self , cmd_parts , application ):
116
+ self ._err .write ("Unknown dot command: %s\n " % cmd_parts [0 ])
117
+
118
+
46
119
class AWSShell (object ):
47
120
"""Encapsulates the ui, completer, command history, docs, and config.
48
121
@@ -81,12 +154,13 @@ class AWSShell(object):
81
154
def __init__ (self , completer , model_completer , docs ):
82
155
self .completer = completer
83
156
self .model_completer = model_completer
84
- self .memory_history = InMemoryHistory ()
157
+ self .history = InMemoryHistory ()
85
158
self .file_history = FileHistory (build_config_file_path ('history' ))
86
159
self ._cli = None
87
160
self ._docs = docs
88
161
self .current_docs = u''
89
162
self .refresh_cli = False
163
+ self ._dot_cmd = DotCommandHandler ()
90
164
self .load_config ()
91
165
92
166
def load_config (self ):
@@ -136,23 +210,14 @@ def run(self):
136
210
if text .startswith ('.' ):
137
211
# These are special commands. The only one supported for
138
212
# now is .edit.
139
- if text .startswith ('.edit' ):
140
- # TODO: Use EDITOR env var.
141
- all_commands = '\n ' .join (
142
- ['aws ' + h for h in list (self .memory_history )
143
- if not h .startswith (('.' , '!' ))])
144
- with tempfile .NamedTemporaryFile ('w' ) as f :
145
- f .write (all_commands )
146
- f .flush ()
147
- p = subprocess .Popen (['vim' , f .name ])
148
- p .communicate ()
213
+ self ._dot_cmd .handle_cmd (text , application = self )
149
214
else :
150
215
if text .startswith ('!' ):
151
216
# Then run the rest as a normally shell command.
152
217
full_cmd = text [1 :]
153
218
else :
154
219
full_cmd = 'aws ' + text
155
- self .memory_history .append (full_cmd )
220
+ self .history .append (full_cmd )
156
221
self .current_docs = u''
157
222
self .cli .buffers ['clidocs' ].reset (
158
223
initial_document = Document (self .current_docs ,
0 commit comments