diff --git a/doc_src/cmds/commandline.rst b/doc_src/cmds/commandline.rst index ac9568e6a..3f9206ae1 100644 --- a/doc_src/cmds/commandline.rst +++ b/doc_src/cmds/commandline.rst @@ -26,6 +26,12 @@ The following options are available: If no argument is given, the current cursor position is printed, otherwise the argument is interpreted as the new cursor position. If one of the options **-j**, **-p** or **-t** is given, the position is relative to the respective substring instead of the entire command line buffer. +**-B** or **--selection-start** + Get current position of the selection start in the buffer. + +**-E** or **--selection-end** + Get current position of the selection end in the buffer. + **-f** or **--function** Causes any additional arguments to be interpreted as input functions, and puts them into the queue, so that they will be read before any additional actual key presses are. This option cannot be combined with any other option. diff --git a/share/completions/commandline.fish b/share/completions/commandline.fish index 716016b2f..6789cc835 100644 --- a/share/completions/commandline.fish +++ b/share/completions/commandline.fish @@ -16,6 +16,8 @@ complete -c commandline -s o -l tokenize -d "Print each token on a separate line complete -c commandline -s I -l input -d "Specify command to operate on" complete -c commandline -s C -l cursor -d "Set/get cursor position, not buffer contents" +complete -c commandline -s B -l selection-start -d "Get current selection starting position" +complete -c commandline -s E -l selection-end -d "Get current selection ending position" complete -c commandline -s L -l line -d "Print the line that the cursor is on" complete -c commandline -s S -l search-mode -d "Return true if performing a history search" complete -c commandline -s P -l paging-mode -d "Return true if showing pager content" diff --git a/src/builtins/commandline.cpp b/src/builtins/commandline.cpp index 0c7492281..0a0440fc4 100644 --- a/src/builtins/commandline.cpp +++ b/src/builtins/commandline.cpp @@ -142,6 +142,8 @@ maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, const bool tokenize = false; bool cursor_mode = false; + bool selection_start_mode = false; + bool selection_end_mode = false; bool line_mode = false; bool search_mode = false; bool paging_mode = false; @@ -152,7 +154,7 @@ maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, const const auto &ld = parser.libdata(); - static const wchar_t *const short_options = L":abijpctforhI:CLSsP"; + static const wchar_t *const short_options = L":abijpctforhI:CBELSsP"; static const struct woption long_options[] = {{L"append", no_argument, nullptr, 'a'}, {L"insert", no_argument, nullptr, 'i'}, {L"replace", no_argument, nullptr, 'r'}, @@ -167,6 +169,8 @@ maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, const {L"help", no_argument, nullptr, 'h'}, {L"input", required_argument, nullptr, 'I'}, {L"cursor", no_argument, nullptr, 'C'}, + {L"selection-start", no_argument, nullptr, 'B'}, + {L"selection-end", no_argument, nullptr, 'E'}, {L"line", no_argument, nullptr, 'L'}, {L"search-mode", no_argument, nullptr, 'S'}, {L"paging-mode", no_argument, nullptr, 'P'}, @@ -227,6 +231,14 @@ maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, const cursor_mode = true; break; } + case 'B': { + selection_start_mode = true; + break; + } + case 'E': { + selection_end_mode = true; + break; + } case 'L': { line_mode = true; break; @@ -274,7 +286,7 @@ maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, const // Check for invalid switch combinations. if (buffer_part || cut_at_cursor || append_mode || tokenize || cursor_mode || line_mode || - search_mode || paging_mode) { + search_mode || paging_mode || selection_start_mode || selection_end_mode) { streams.err.append_format(BUILTIN_ERR_COMBO, argv[0]); builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; @@ -324,6 +336,12 @@ maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, const } // Check for invalid switch combinations. + if ((selection_start_mode || selection_end_mode) && (argc - w.woptind)) { + streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, argv[0]); + builtin_print_error_trailer(parser, streams.err, cmd); + return STATUS_INVALID_ARGS; + } + if ((search_mode || line_mode || cursor_mode || paging_mode) && (argc - w.woptind > 1)) { streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, argv[0]); builtin_print_error_trailer(parser, streams.err, cmd); @@ -379,6 +397,24 @@ maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, const return (state.pager_mode && state.pager_fully_disclosed) ? 0 : 1; } + if (selection_start_mode) { + if (!rstate.selection) { + return STATUS_CMD_ERROR; + } + source_offset_t start = rstate.selection->start; + streams.out.append_format(L"%lu\n", static_cast(start)); + return STATUS_CMD_OK; + } + + if (selection_end_mode) { + if (!rstate.selection) { + return STATUS_CMD_ERROR; + } + source_offset_t end = rstate.selection->end(); + streams.out.append_format(L"%lu\n", static_cast(end)); + return STATUS_CMD_OK; + } + // At this point we have (nearly) exhausted the options which always operate on the true command // line. Now we respect the possibility of a transient command line due to evaluating a wrapped // completion. Don't do this in cursor_mode: it makes no sense to move the cursor based on a