Skip to content

Commit

Permalink
fixed de-indentation of tabs (aka 4 spaces)
Browse files Browse the repository at this point in the history
  • Loading branch information
chaudum committed Oct 9, 2017
1 parent 6c5820a commit 0a24a30
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 28 deletions.
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
==========

- Fixed an issue where BACKSPACE would delete more characters before the
cursor than expected.

- Added support for pasting and executing multiple statements at once.

- Added back support for multiline table headers
Expand Down
61 changes: 61 additions & 0 deletions src/crate/crash/keybinding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# vim: set fileencodings=utf-8
# -*- coding: utf-8; -*-
#
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
# license agreements. See the NOTICE file distributed with this work for
# additional information regarding copyright ownership. Crate licenses
# this file to you under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may
# obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# However, if you have executed another commercial license agreement
# with Crate these terms will supersede the license and you may use the
# software solely pursuant to the terms of the relevant commercial agreement.


import re
from prompt_toolkit.keys import Keys
from prompt_toolkit.filters import Condition

TAB_WIDTH = 4
WHITESPACE_RE = re.compile(r'\s+$')


def doc_condition(fn):
return lambda cli: fn(cli.current_buffer.document)


def _is_start_of_multiline(doc):
return doc.text and not doc.get_word_before_cursor()


def _line_ends_with_tab(doc):
trailing_ws = WHITESPACE_RE.findall(doc.current_line_before_cursor)
return (
not doc.get_word_before_cursor() and
trailing_ws and
len(trailing_ws[0]) % TAB_WIDTH == 0
)


def bind_keys(registry):

@registry.add_binding(Keys.Tab,
filter=Condition(
doc_condition(_is_start_of_multiline)))
def on_tab(event):
event.cli.current_buffer.insert_text(' ' * TAB_WIDTH)

registry.add_binding(Keys.Backspace,
filter=Condition(
doc_condition(_line_ends_with_tab)))
def on_backspace(event):
event.cli.current_buffer.delete_before_cursor(TAB_WIDTH)
30 changes: 2 additions & 28 deletions src/crate/crash/repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@
ConditionalProcessor
)
from prompt_toolkit.key_binding.manager import KeyBindingManager
from prompt_toolkit.keys import Keys
from prompt_toolkit.shortcuts import (create_output,
create_eventloop)

from .commands import Command
from .layout import create_layout
from .keybinding import bind_keys

MAX_HISTORY_LENGTH = 10000

Expand Down Expand Up @@ -274,32 +274,6 @@ def create_buffer(cmd, history_file):
buffer.complete_while_typing = lambda cli=None: cmd.should_autocomplete()
return buffer


def _bind_keys(registry):

def _is_start_of_multiline(cli):
doc = cli.current_buffer.document
word = doc.get_word_before_cursor()
return doc.text and not word

@registry.add_binding(Keys.Tab, filter=Condition(_is_start_of_multiline))
def _(event):
event.cli.current_buffer.insert_text(' ')

def _bs_should_deindent(cli):
doc = cli.current_buffer.document
start_of_line_pos = doc.get_start_of_line_position()
return (
not doc.get_word_before_cursor() and
start_of_line_pos != 0 and
start_of_line_pos % 4 == 0
)

@registry.add_binding(Keys.Backspace, filter=Condition(_bs_should_deindent))
def _(event):
event.cli.current_buffer.delete_before_cursor(4)


def _get_toolbar_tokens(is_conn_available, username, active_servers):
tokens = []
if is_conn_available():
Expand Down Expand Up @@ -327,7 +301,7 @@ def session_toolbar(cli):
enable_system_bindings=True,
enable_open_in_editor=True
)
_bind_keys(key_binding_manager.registry)
bind_keys(key_binding_manager.registry)
layout = create_layout(
message=u'cr> ',
multiline=True,
Expand Down
46 changes: 46 additions & 0 deletions src/crate/crash/test_keybinding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
# license agreements. See the NOTICE file distributed with this work for
# additional information regarding copyright ownership. Crate licenses
# this file to you under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may
# obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# However, if you have executed another commercial license agreement
# with Crate these terms will supersede the license and you may use the
# software solely pursuant to the terms of the relevant commercial agreement.

from unittest import TestCase
from prompt_toolkit.document import Document
from .keybinding import _is_start_of_multiline, _line_ends_with_tab


doc = lambda t: Document(t, len(t))
is_start_of_multiline = lambda t: _is_start_of_multiline(doc(t))
line_ends_with_tab = lambda t: _line_ends_with_tab(doc(t))


class TabIndentTest(TestCase):

def test_indent(self):
self.assertFalse(is_start_of_multiline(u''))
self.assertFalse(is_start_of_multiline(u'SELECT'))
self.assertFalse(is_start_of_multiline(u'SELECT\n*'))
self.assertTrue(is_start_of_multiline(u'SELECT\n'))
self.assertTrue(is_start_of_multiline(u'SELECT\n '))
self.assertTrue(is_start_of_multiline(u'\n'))

def test_deindent(self):
self.assertFalse(line_ends_with_tab(u''))
self.assertFalse(line_ends_with_tab(u'SELECT'))
self.assertFalse(line_ends_with_tab(u'SELECT '))
self.assertFalse(line_ends_with_tab(u'SELECT \n'))
self.assertTrue(line_ends_with_tab(u'SELECT '))
self.assertTrue(line_ends_with_tab(u'SELECT\n '))
2 changes: 2 additions & 0 deletions src/crate/crash/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from .test_sysinfo import SysInfoTest
from .test_repl import SQLCompleterTest, AutoCapitalizeTest, CrashBufferTest, ToolbarTest
from .test_config import ConfigurationTest
from .test_keybinding import TabIndentTest


class CrateTestCmd(CrateCmd):
Expand Down Expand Up @@ -124,5 +125,6 @@ def test_suite():
suite.addTest(unittest.makeSuite(CrashBufferTest))
suite.addTest(unittest.makeSuite(ConfigurationTest))
suite.addTest(unittest.makeSuite(TestGetInformationSchemaQuery))
suite.addTest(unittest.makeSuite(TabIndentTest))

return suite

0 comments on commit 0a24a30

Please sign in to comment.