mirror of
https://github.com/dbcli/pgcli.git
synced 2024-10-06 02:07:53 +03:00
Handle a multi-line query on Enter key-press (fixes #1031)
Use a (conditional) Enter key-binding to force-handle a multi-line buffer, rather than doing so by (conditionally) disabling the multiline mode of prompt_toolkit. This has the benefit of being more efficient (the multiline Condition filter is called very often, which (due to the repeated query parsing) causes editing to become slow with a large buffer that ends in a semicolon), clearer in intent (we want to force-handle the query, rather than (temporarily) disable multiline mode which indirectly forces the buffer to be handled) and avoids a bug in multi-line history search (issue #1031)
This commit is contained in:
parent
d5cdd2ad4e
commit
7f44748149
@ -14,6 +14,7 @@ Bug fixes:
|
||||
* Empty query caused error message (#1019) (Thanks: `Sebastian Janko`_)
|
||||
* History navigation bindings in multiline queries (#1004) (Thanks: `Pedro Ferrari`_)
|
||||
* Can't connect to pgbouncer database (#1093). (Thanks: `Irina Truong`_)
|
||||
* Fix broken multi-line history search (#1031). (Thanks: `Owen Stephens`_)
|
||||
|
||||
Internal:
|
||||
---------
|
||||
|
@ -9,6 +9,8 @@ from prompt_toolkit.filters import (
|
||||
has_selection,
|
||||
)
|
||||
|
||||
from .pgbuffer import multi_line_buffer_should_be_handled
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -94,6 +96,15 @@ def pgcli_bindings(pgcli):
|
||||
event.current_buffer.complete_state = None
|
||||
event.app.current_buffer.complete_state = None
|
||||
|
||||
# When using multi_line input mode the buffer is not handled on Enter (a new line is
|
||||
# inserted instead), so we force the handling if one of several conditions are True
|
||||
@kb.add(
|
||||
"enter",
|
||||
filter=~completion_is_selected & multi_line_buffer_should_be_handled(pgcli),
|
||||
)
|
||||
def _(event):
|
||||
event.current_buffer.validate_and_handle()
|
||||
|
||||
@kb.add("escape", "enter")
|
||||
def _(event):
|
||||
"""Introduces a line break regardless of multi-line mode or not."""
|
||||
|
@ -35,7 +35,7 @@ from prompt_toolkit.completion import DynamicCompleter, ThreadedCompleter
|
||||
from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
|
||||
from prompt_toolkit.shortcuts import PromptSession, CompleteStyle
|
||||
from prompt_toolkit.document import Document
|
||||
from prompt_toolkit.filters import HasFocus, IsDone
|
||||
from prompt_toolkit.filters import HasFocus, IsDone, Condition
|
||||
from prompt_toolkit.lexers import PygmentsLexer
|
||||
from prompt_toolkit.layout.processors import (
|
||||
ConditionalProcessor,
|
||||
@ -53,7 +53,6 @@ from .pgcompleter import PGCompleter
|
||||
from .pgtoolbar import create_toolbar_tokens_func
|
||||
from .pgstyle import style_factory, style_factory_output
|
||||
from .pgexecute import PGExecute
|
||||
from .pgbuffer import pg_is_multiline
|
||||
from .completion_refresher import CompletionRefresher
|
||||
from .config import (
|
||||
get_casing_file,
|
||||
@ -810,7 +809,7 @@ class PGCli(object):
|
||||
],
|
||||
auto_suggest=AutoSuggestFromHistory(),
|
||||
tempfile_suffix=".sql",
|
||||
multiline=pg_is_multiline(self),
|
||||
multiline=Condition(lambda: self.multi_line),
|
||||
history=history,
|
||||
completer=ThreadedCompleter(DynamicCompleter(lambda: self.completer)),
|
||||
complete_while_typing=True,
|
||||
|
@ -6,21 +6,6 @@ from prompt_toolkit.application import get_app
|
||||
from .packages.parseutils.utils import is_open_quote
|
||||
|
||||
|
||||
def pg_is_multiline(pgcli):
|
||||
@Condition
|
||||
def cond():
|
||||
doc = get_app().layout.get_buffer_by_name(DEFAULT_BUFFER).document
|
||||
|
||||
if not pgcli.multi_line:
|
||||
return False
|
||||
if pgcli.multiline_mode == "safe":
|
||||
return True
|
||||
else:
|
||||
return not _multiline_exception(doc.text)
|
||||
|
||||
return cond
|
||||
|
||||
|
||||
def _is_complete(sql):
|
||||
# A complete command is an sql statement that ends with a semicolon, unless
|
||||
# there's an open quote surrounding it, as is common when writing a
|
||||
@ -28,17 +13,32 @@ def _is_complete(sql):
|
||||
return sql.endswith(";") and not is_open_quote(sql)
|
||||
|
||||
|
||||
def _multiline_exception(text):
|
||||
text = text.strip()
|
||||
return (
|
||||
text.startswith("\\")
|
||||
or text.endswith(r"\e") # Special Command
|
||||
or text.endswith(r"\G") # Special Command
|
||||
or _is_complete(text) # Ended with \e which should launch the editor
|
||||
or (text == "exit") # A complete SQL command
|
||||
or (text == "quit") # Exit doesn't need semi-colon
|
||||
or (text == ":q") # Quit doesn't need semi-colon
|
||||
or ( # To all the vim fans out there
|
||||
text == ""
|
||||
) # Just a plain enter without any text
|
||||
)
|
||||
"""
|
||||
Returns True if the input mode is multi-line using psql mode, and the main
|
||||
buffer's contents indicate that it should be handled, False otherwise. This
|
||||
method is required since by default prompt_toolkit would not handle a buffer on
|
||||
Enter keypress when in multi-line mode.
|
||||
"""
|
||||
|
||||
|
||||
def multi_line_buffer_should_be_handled(pgcli):
|
||||
@Condition
|
||||
def cond():
|
||||
if not pgcli.multi_line or pgcli.multiline_mode == "safe":
|
||||
return False
|
||||
|
||||
doc = get_app().layout.get_buffer_by_name(DEFAULT_BUFFER).document
|
||||
text = doc.text.strip()
|
||||
|
||||
return (
|
||||
text.startswith("\\") # Special Command
|
||||
or text.endswith(r"\e") # Special Command
|
||||
or text.endswith(r"\G") # Ended with \e which should launch the editor
|
||||
or _is_complete(text) # A complete SQL command
|
||||
or (text == "exit") # Exit doesn't need semi-colon
|
||||
or (text == "quit") # Quit doesn't need semi-colon
|
||||
or (text == ":q") # To all the vim fans out there
|
||||
or (text == "") # Just a plain enter without any text
|
||||
)
|
||||
|
||||
return cond
|
||||
|
Loading…
Reference in New Issue
Block a user