summaryrefslogtreecommitdiff
path: root/cmdbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmdbuf.c')
-rw-r--r--cmdbuf.c189
1 files changed, 138 insertions, 51 deletions
diff --git a/cmdbuf.c b/cmdbuf.c
index 73dd2975b100..f2963cf4c9da 100644
--- a/cmdbuf.c
+++ b/cmdbuf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1984-2024 Mark Nudelman
+ * Copyright (C) 1984-2025 Mark Nudelman
*
* You may distribute under the terms of either the GNU General Public
* License or the Less License, as specified in the README file.
@@ -24,6 +24,8 @@ extern int sc_width;
extern int utf_mode;
extern int no_hist_dups;
extern int marks_modified;
+extern int no_paste;
+public lbool pasting = FALSE;
static char cmdbuf[CMDBUF_SIZE]; /* Buffer for holding a multi-char command */
static int cmd_col; /* Current column of the cursor */
@@ -34,7 +36,6 @@ static lbool literal; /* Next input char should not be interpreted */
static size_t updown_match; /* Prefix length in up/down movement */
static lbool have_updown_match = FALSE;
-#if TAB_COMPLETE_FILENAME
static int cmd_complete(int action);
/*
* These variables are statics used by cmd_complete.
@@ -45,7 +46,6 @@ static char *tk_original;
static constant char *tk_ipoint;
static constant char *tk_trial = NULL;
static struct textlist tk_tlist;
-#endif
static int cmd_left();
static int cmd_right();
@@ -183,6 +183,16 @@ public int len_cmdbuf(void)
}
/*
+ * Is the command buffer empty?
+ * It is considered nonempty if there is any text in it,
+ * or if a multibyte command is being entered but not yet complete.
+ */
+public lbool cmdbuf_empty(void)
+{
+ return cp == cmdbuf && cmd_mbc_buf_len == 0;
+}
+
+/*
* Common part of cmd_step_right() and cmd_step_left().
* {{ Returning pwidth and bswidth separately is a historical artifact
* since they're always the same. Maybe clean this up someday. }}
@@ -305,6 +315,16 @@ public void cmd_repaint(constant char *old_cp)
}
/*
+ * Repaint the entire line, without moving the cursor.
+ */
+static void cmd_repaint_curr(void)
+{
+ char *save_cp = cp;
+ cmd_home();
+ cmd_repaint(save_cp);
+}
+
+/*
* Shift the cmdbuf display left a half-screen.
*/
static void cmd_lshift(void)
@@ -804,17 +824,13 @@ public void cmd_accept(void)
* CC_OK Line edit function done.
* CC_QUIT The char requests the current command to be aborted.
*/
-static int cmd_edit(char c)
+static int cmd_edit(char c, lbool stay_in_completion)
{
int action;
int flags;
-#if TAB_COMPLETE_FILENAME
-#define not_in_completion() in_completion = 0
-#else
-#define not_in_completion(void)
-#endif
-
+#define not_in_completion() do { if (!stay_in_completion) in_completion = FALSE; } while(0)
+
/*
* See if the char is indeed a line-editing command.
*/
@@ -826,21 +842,35 @@ static int cmd_edit(char c)
*/
flags |= ECF_NOHISTORY;
#endif
+
+ /*
+ * Don't accept completion cmds in contexts
+ * such as search pattern, digits, etc.
+ */
+ if ((curr_mlist == NULL && (curr_cmdflags & CF_OPTION))
#if TAB_COMPLETE_FILENAME
- if (curr_mlist == ml_search || curr_mlist == NULL)
- /*
- * Don't accept file-completion cmds in contexts
- * such as search pattern, digits, long option name, etc.
- */
- flags |= ECF_NOCOMPLETE;
+ || curr_mlist == ml_examine || curr_mlist == ml_shell
#endif
+ )
+ ; /* allow completion */
+ else
+ flags |= ECF_NOCOMPLETE;
action = editchar(c, flags);
+ if (is_ignoring_input(action))
+ return (CC_OK);
switch (action)
{
case A_NOACTION:
return (CC_OK);
+ case EC_START_PASTE:
+ if (no_paste)
+ pasting = TRUE;
+ return (CC_OK);
+ case EC_END_PASTE:
+ stop_ignoring_input();
+ return (CC_OK);
case EC_RIGHT:
not_in_completion();
return (cmd_right());
@@ -903,19 +933,16 @@ static int cmd_edit(char c)
not_in_completion();
return (cmd_updown(action));
#endif
-#if TAB_COMPLETE_FILENAME
case EC_F_COMPLETE:
case EC_B_COMPLETE:
case EC_EXPAND:
return (cmd_complete(action));
-#endif
default:
not_in_completion();
return (CC_PASS);
}
}
-#if TAB_COMPLETE_FILENAME
/*
* Insert a string into the command buffer, at the current position.
*/
@@ -937,6 +964,18 @@ static int cmd_istr(constant char *str)
}
/*
+ * Set tk_original to word.
+ */
+static void set_tk_original(constant char *word)
+{
+ if (tk_original != NULL)
+ free(tk_original);
+ tk_original = (char *) ecalloc(ptr_diff(cp,word)+1, sizeof(char));
+ strncpy(tk_original, word, ptr_diff(cp,word));
+}
+
+#if TAB_COMPLETE_FILENAME
+/*
* Find the beginning and end of the "current" word.
* This is the word which the cursor (cp) is inside or at the end of.
* Return pointer to the beginning of the word and put the
@@ -1024,24 +1063,16 @@ static char * delimit_word(void)
}
/*
- * Set things up to enter completion mode.
+ * Set things up to enter file completion mode.
* Expand the word under the cursor into a list of filenames
* which start with that word, and set tk_text to that list.
*/
-static void init_compl(void)
+static void init_file_compl(void)
{
char *word;
char c;
/*
- * Get rid of any previous tk_text.
- */
- if (tk_text != NULL)
- {
- free(tk_text);
- tk_text = NULL;
- }
- /*
* Find the original (uncompleted) word in the command buffer.
*/
word = delimit_word();
@@ -1052,13 +1083,7 @@ static void init_compl(void)
* where the original (uncompleted) word now sits.
*/
tk_ipoint = word;
- /*
- * Save the original (uncompleted) word
- */
- if (tk_original != NULL)
- free(tk_original);
- tk_original = (char *) ecalloc(ptr_diff(cp,word)+1, sizeof(char));
- strncpy(tk_original, word, ptr_diff(cp,word));
+ set_tk_original(word);
/*
* Get the expanded filename.
* This may result in a single filename, or
@@ -1086,6 +1111,17 @@ static void init_compl(void)
}
*cp = c;
}
+#endif /* TAB_COMPLETE_FILENAME */
+
+/*
+ * Set things up to enter option completion mode.
+ */
+static void init_opt_compl(void)
+{
+ tk_ipoint = cmdbuf;
+ set_tk_original(cmdbuf);
+ tk_text = findopts_name(cmdbuf);
+}
/*
* Return the next word in the current completion list.
@@ -1120,7 +1156,19 @@ static int cmd_complete(int action)
* use the first word in the expansion
* (or the entire expansion if we're doing EC_EXPAND).
*/
- init_compl();
+ if (tk_text != NULL)
+ {
+ free(tk_text);
+ tk_text = NULL;
+ }
+ if (curr_cmdflags & CF_OPTION)
+ init_opt_compl();
+ else
+#if TAB_COMPLETE_FILENAME
+ init_file_compl();
+#else
+ quit(QUIT_ERROR); /* cannot happen */
+#endif /* TAB_COMPLETE_FILENAME */
if (tk_text == NULL)
{
bell();
@@ -1195,25 +1243,20 @@ fail:
return (CC_OK);
}
-#endif /* TAB_COMPLETE_FILENAME */
-
/*
- * Process a single character of a multi-character command, such as
- * a number, or the pattern of a search command.
+ * Build a UTF-8 char in cmd_mbc_buf.
* Returns:
- * CC_OK The char was accepted.
- * CC_QUIT The char requests the command to be aborted.
- * CC_ERROR The char could not be accepted due to an error.
+ * CC_OK Char has been stored but we don't have a complete UTF-8 sequence yet.
+ * CC_ERROR This is an invalid UTF-8 sequence.
+ * CC_PASS There is a complete UTF-8 sequence in cmd_mbc_buf.
+ * The length of the complete sequence is returned in *plen.
*/
-public int cmd_char(char c)
+static int cmd_uchar(char c, size_t *plen)
{
- int action;
- size_t len;
-
if (!utf_mode)
{
cmd_mbc_buf[0] = c;
- len = 1;
+ *plen = 1;
} else
{
/* Perform strict validation in all possible cases. */
@@ -1262,9 +1305,26 @@ public int cmd_char(char c)
goto retry;
}
- len = (size_t) cmd_mbc_buf_len; /*{{type-issue}}*/
+ *plen = (size_t) cmd_mbc_buf_len; /*{{type-issue}}*/
cmd_mbc_buf_len = 0;
}
+ return (CC_PASS);
+}
+
+/*
+ * Process a single character of a multi-character command, such as
+ * a number, or the pattern of a search command.
+ * Returns:
+ * CC_OK The char was accepted.
+ * CC_QUIT The char requests the command to be aborted.
+ * CC_ERROR The char could not be accepted due to an error.
+ */
+static int cmd_char2(char c, lbool stay_in_completion)
+{
+ size_t len;
+ int action = cmd_uchar(c, &len);
+ if (action != CC_PASS)
+ return (action);
if (literal)
{
@@ -1280,7 +1340,7 @@ public int cmd_char(char c)
*/
if (in_mca() && len == 1)
{
- action = cmd_edit(c);
+ action = cmd_edit(c, stay_in_completion);
switch (action)
{
case CC_OK:
@@ -1297,6 +1357,30 @@ public int cmd_char(char c)
return (cmd_ichar(cmd_mbc_buf, len));
}
+public int cmd_char(char c)
+{
+ return cmd_char2(c, FALSE);
+}
+
+/*
+ * Copy an ASCII string to the command buffer.
+ */
+public int cmd_setstring(constant char *s, lbool uc)
+{
+ while (*s != '\0')
+ {
+ int action;
+ char c = *s++;
+ if (uc && ASCII_IS_LOWER(c))
+ c = ASCII_TO_UPPER(c);
+ action = cmd_char2(c, TRUE);
+ if (action != CC_OK)
+ return (action);
+ }
+ cmd_repaint_curr();
+ return (CC_OK);
+}
+
/*
* Return the number currently in the command buffer.
*/
@@ -1464,6 +1548,7 @@ static void read_cmdhist2(void (*action)(void*,struct mlist*,constant char*), vo
#else
ml = NULL;
skip = NULL;
+ (void) skip_shell;
#endif
} else if (strcmp(line, HISTFILE_MARK_SECTION) == 0)
{
@@ -1674,6 +1759,8 @@ public void save_cmdhist(void)
skip_search = mlist_size(&mlist_search) - histsize;
#if SHELL_ESCAPE || PIPEC
skip_shell = mlist_size(&mlist_shell) - histsize;
+#else
+ skip_shell = 0; /* not actually used */
#endif
fprintf(fout, "%s\n", HISTFILE_FIRST_LINE);
ctx.fout = fout;