Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ Changes for crash
Unreleased
==========

- Automatically capitalize keywords while typing,
e.g. ``select`` -> ``SELECT``

- Automatically suggest and complete to ``UPPERCASE`` keywords
when using autocomplete.

Expand Down
5 changes: 5 additions & 0 deletions docs/cli.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ The ``crash`` binary supports several command line arguments.
| | overlay for suggestions. |
| | Disabling autocomplete removes this limitation. |
+---------------------------------------+--------------------------------------------------+
| ``-C`` , ``--no-autocapitalize`` | Disable automatic capitalization of SQL keywords |
| | while typing. |
+---------------------------------------+--------------------------------------------------+

Example Usage
=============
Expand Down Expand Up @@ -98,6 +101,8 @@ You can get a list of commands by typing ``\?``:
+----------------------+------------------------------------------------------------------------------------+
| ``\autocomplete`` | Turn autocomplete feature on or off. Works as a toggle. |
+----------------------+------------------------------------------------------------------------------------+
| ``\autocapitalize`` | Turn automatic capitalization for SQL keywords or off. Works as a toggle. |
+----------------------+------------------------------------------------------------------------------------+

===============
Status Messages
Expand Down
14 changes: 12 additions & 2 deletions src/crate/crash/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ def _conf_or_default(key, value):
dest='autocomplete',
default=_conf_or_default('autocomplete', True),
help='use -A to disable SQL autocompletion')
parser.add_argument('-C', '--no-autocapitalize', action='store_false',
dest='autocapitalize',
default=_conf_or_default('autocapitalize', True),
help='use -C to disable automatic capitalization of SQL keywords')

parser.add_argument('--history', type=str,
help='the history file to use', default=HISTORY_PATH)
Expand Down Expand Up @@ -181,7 +185,8 @@ def __init__(self,
connection=None,
error_trace=False,
is_tty=True,
autocomplete=True):
autocomplete=True,
autocapitalize=True):
self.error_trace = error_trace
self.connection = connection or connect(error_trace=error_trace)
self.cursor = self.connection.cursor()
Expand All @@ -201,13 +206,17 @@ def __init__(self,
self.commands.update(built_in_commands)
self.logger = ColorPrinter(is_tty)
self._autocomplete = autocomplete
self._autocapitalize = autocapitalize

def get_num_columns(self):
return 80

def should_autocomplete(self):
return self._autocomplete

def should_autocapitalize(self):
return self._autocapitalize

def pprint(self, rows, cols):
result = Result(cols,
rows,
Expand Down Expand Up @@ -432,7 +441,8 @@ def main():
error_trace=error_trace,
output_writer=output_writer,
is_tty=is_tty,
autocomplete=args.autocomplete)
autocomplete=args.autocomplete,
autocapitalize=args.autocapitalize)
if error_trace:
# log CONNECT command only in verbose mode
cmd._connect(crate_hosts)
Expand Down
12 changes: 12 additions & 0 deletions src/crate/crash/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ def __call__(self, cmd, *args, **kwargs):
)


class ToggleAutoCapitalizeCommand(Command):
""" toggle automatic capitalization of SQL keywords """

@noargs_command
def __call__(self, cmd, *args, **kwargs):
cmd._autocapitalize = not cmd._autocapitalize
return 'Auto-capitalization {0}'.format(
cmd._autocapitalize and 'ON' or 'OFF'
)


class CheckBaseCommand(Command):

check_name = None
Expand Down Expand Up @@ -198,5 +209,6 @@ def __call__(self, cmd, check_name=None, **kwargs):
'r': ReadFileCommand(),
'format': SwitchFormatCommand(),
'autocomplete': ToggleAutocompleteCommand(),
'autocapitalize': ToggleAutoCapitalizeCommand(),
'check': CheckCommand(),
}
22 changes: 21 additions & 1 deletion src/crate/crash/repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,25 @@ def is_multiline():
*args, is_multiline=is_multiline, **kwargs)


class Capitalizer:

def __init__(self, cmd):
self.cmd = cmd
self.last_changed = None

def __call__(self, buffer):
if not self.cmd.should_autocapitalize():
return
last_word = buffer.document.get_word_before_cursor(WORD=True)
if not last_word.isupper() and last_word.lower() in SQLCompleter.keywords:
buffer.delete_before_cursor(len(last_word))
buffer.insert_text(last_word.upper(), fire_event=False)
self.last_changed = last_word
elif self.last_changed and last_word.startswith(self.last_changed.upper()):
buffer.delete_before_cursor(len(last_word))
buffer.insert_text(self.last_changed + last_word[-1:], fire_event=False)


def loop(cmd, history_file):
key_binding_manager = KeyBindingManager(
enable_search=True,
Expand All @@ -190,7 +209,8 @@ def loop(cmd, history_file):
buffer = CrashBuffer(
history=TruncatedFileHistory(history_file, max_length=MAX_HISTORY_LENGTH),
accept_action=AcceptAction.RETURN_DOCUMENT,
completer=SQLCompleter(cmd)
completer=SQLCompleter(cmd),
on_text_insert=Capitalizer(cmd)
)
buffer.complete_while_typing = lambda cli=None: cmd.should_autocomplete()
application = Application(
Expand Down
1 change: 1 addition & 0 deletions src/crate/crash/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ def test_help_command(self):
command = CrateCmd(is_tty=False)
expected = "\n".join([
'\\? print this help',
'\\autocapitalize toggle automatic capitalization of SQL keywords',
'\\autocomplete toggle autocomplete',
'\\c connect to the given server, e.g.: \connect localhost:4200',
'\\check print failed cluster and/or node checks, e.g. \check nodes',
Expand Down
15 changes: 14 additions & 1 deletion src/crate/crash/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
from six import StringIO
from unittest import TestCase
from mock import patch, MagicMock
from .commands import ReadFileCommand, ToggleAutocompleteCommand, \
from .commands import ReadFileCommand, \
ToggleAutocompleteCommand, ToggleAutoCapitalizeCommand , \
NodeCheckCommand, ClusterCheckCommand, CheckCommand

from .command import CrateCmd
Expand Down Expand Up @@ -76,6 +77,18 @@ def test_toggle_output(self, fake_cmd):
self.assertEqual(output, 'Autocomplete ON')


class ToggleAutoCapitalizeCommandTest(TestCase):

@patch('crate.crash.command.CrateCmd')
def test_toggle_output(self, fake_cmd):
fake_cmd._autocapitalization = True
command = ToggleAutoCapitalizeCommand()
output = command(fake_cmd)
self.assertEqual(output, 'Auto-capitalization OFF')
output = command(fake_cmd)
self.assertEqual(output, 'Auto-capitalization ON')


class ShowTablesCommandTest(TestCase):

def test_post_0_57(self):
Expand Down
64 changes: 56 additions & 8 deletions src/crate/crash/test_repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,70 @@
# software solely pursuant to the terms of the relevant commercial agreement.

from unittest import TestCase
from .repl import SQLCompleter
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.document import Document
from .repl import SQLCompleter, Capitalizer
from .command import CrateCmd


class SQLCompleterTest(TestCase):

def setUp(self):
self.cmd = CrateCmd()
self.completer = SQLCompleter(self.cmd)
cmd = CrateCmd()
self.completer = SQLCompleter(cmd)

def test_get_builtin_command_completions(self):
c = self.completer
result = sorted(list(c.get_command_completions('\\c')))
result = sorted(list(self.completer.get_command_completions('\\c')))
self.assertEqual(result, ['c', 'check', 'connect'])

def test_get_command_completions_format(self):
cmd = CrateCmd()
completer = SQLCompleter(cmd)
result = list(completer.get_command_completions(r'\format dyn'))
result = list(self.completer.get_command_completions(r'\format dyn'))
self.assertEqual(result, ['dynamic'])


class AutoCapitalizeTest(TestCase):

def setUp(self):
cmd = CrateCmd()
self.capitalizer = Capitalizer(cmd)

def test_capitalize(self):
buffer = Buffer()

text = u'selec'
buffer.set_document(Document(text, len(text)))
self.capitalizer(buffer)
self.assertEqual(u'selec', buffer.text)

text = u'select'
buffer.set_document(Document(text, len(text)))
self.capitalizer(buffer)
self.assertEqual(u'SELECT', buffer.text)

text = u'CREATE TABLE "select'
buffer.set_document(Document(text, len(text)))
self.capitalizer(buffer)
self.assertEqual(u'CREATE TABLE "select', buffer.text)

def test_undo_capitalize(self):
buffer = Buffer()

text = u'Selec'
buffer.set_document(Document(text, len(text)))
self.capitalizer(buffer)
self.assertEqual(u'Selec', buffer.text)

text = buffer.text + 't'
buffer.set_document(Document(text, len(text)))
self.capitalizer(buffer)
self.assertEqual(u'SELECT', buffer.text)

text = buffer.text + 'i'
buffer.set_document(Document(text, len(text)))
self.capitalizer(buffer)
self.assertEqual(u'Selecti', buffer.text)

text = buffer.text + 'on'
buffer.set_document(Document(text, len(text)))
self.capitalizer(buffer)
self.assertEqual(u'Selection', buffer.text)
3 changes: 2 additions & 1 deletion src/crate/crash/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from .test_commands import ReadFileCommandTest, ToggleAutocompleteCommandTest, \
ChecksCommandTest, ShowTablesCommandTest
from .test_sysinfo import SysInfoTest
from .test_repl import SQLCompleterTest
from .test_repl import SQLCompleterTest, AutoCapitalizeTest
from .test_config import ConfigurationTest


Expand Down Expand Up @@ -100,6 +100,7 @@ def test_suite():
suite.addTest(unittest.makeSuite(ChecksCommandTest))
suite.addTest(unittest.makeSuite(ShowTablesCommandTest))
suite.addTest(unittest.makeSuite(SQLCompleterTest))
suite.addTest(unittest.makeSuite(AutoCapitalizeTest))
suite.addTest(unittest.makeSuite(ConfigurationTest))
suite.addTest(unittest.makeSuite(TestGetInformationSchemaQuery))

Expand Down