git: 109324d5e7ab - releng/15.1 - MFV less v691

From: Colin Percival <cperciva_at_FreeBSD.org>
Date: Thu, 07 May 2026 17:25:10 UTC
The branch releng/15.1 has been updated by cperciva:

URL: https://cgit.FreeBSD.org/src/commit/?id=109324d5e7ab893c15540fe97325b3eeaee88d20

commit 109324d5e7ab893c15540fe97325b3eeaee88d20
Author:     Xin LI <delphij@FreeBSD.org>
AuthorDate: 2026-05-07 03:51:51 +0000
Commit:     Colin Percival <cperciva@FreeBSD.org>
CommitDate: 2026-05-07 17:24:43 +0000

    MFV less v691
    
    Approved by:    re (cperciva)
    Relnotes:       yes
    
    (cherry picked from commit dafba19e42e78cd3d7c9264ece49ddd3d7d70da5)
    
    MFV: less v692.
    
    (cherry picked from commit e2abec625bf07c054f7ac2df2402d6c454113df8)
    (cherry picked from commit 423b0bc492d5264ee518c6569d3c90ee0efb338c)
---
 contrib/less/LICENSE         |    2 +-
 contrib/less/NEWS            |   83 +++
 contrib/less/README          |   60 +-
 contrib/less/brac.c          |    2 +-
 contrib/less/ch.c            |   14 +-
 contrib/less/charset.c       |   31 +-
 contrib/less/charset.h       |    2 +-
 contrib/less/cmd.h           |   26 +-
 contrib/less/cmdbuf.c        |  138 ++--
 contrib/less/command.c       |   87 +--
 contrib/less/compose.uni     |   14 +-
 contrib/less/cvt.c           |    2 +-
 contrib/less/decode.c        |  107 ++-
 contrib/less/edit.c          |   16 +-
 contrib/less/evar.c          |    2 +-
 contrib/less/filename.c      |   20 +-
 contrib/less/fmt.uni         |    2 +-
 contrib/less/forwback.c      |   37 +-
 contrib/less/funcs.h         |   75 ++-
 contrib/less/help.c          |    9 +-
 contrib/less/ifile.c         |   12 +-
 contrib/less/input.c         |    3 +-
 contrib/less/jump.c          |   18 +-
 contrib/less/lang.h          |    5 +-
 contrib/less/less.h          |   19 +-
 contrib/less/less.hlp        |    7 +-
 contrib/less/less.nro        | 1495 ++++++++++++++++++++++++++++--------------
 contrib/less/lessecho.c      |    2 +-
 contrib/less/lessecho.nro    |   37 +-
 contrib/less/lesskey.c       |    2 +-
 contrib/less/lesskey.h       |    2 +-
 contrib/less/lesskey.nro     |  389 +++++++----
 contrib/less/lesskey_parse.c |   37 +-
 contrib/less/lglob.h         |    2 +-
 contrib/less/line.c          |   39 +-
 contrib/less/linenum.c       |    2 +-
 contrib/less/lsystem.c       |   22 +-
 contrib/less/main.c          |   55 +-
 contrib/less/mark.c          |  154 +++--
 contrib/less/omit.uni        |    2 +-
 contrib/less/optfunc.c       |  132 ++--
 contrib/less/option.c        |  134 ++--
 contrib/less/option.h        |    3 +-
 contrib/less/opttbl.c        |   11 +-
 contrib/less/os.c            |   65 +-
 contrib/less/output.c        |   38 +-
 contrib/less/pattern.c       |    2 +-
 contrib/less/pattern.h       |    2 +-
 contrib/less/pckeys.h        |   45 +-
 contrib/less/position.c      |   16 +-
 contrib/less/position.h      |    2 +-
 contrib/less/prompt.c        |   38 +-
 contrib/less/screen.c        |  527 ++++++++++-----
 contrib/less/scrsize.c       |    2 +-
 contrib/less/search.c        |   23 +-
 contrib/less/signal.c        |   30 +-
 contrib/less/tags.c          |    9 +-
 contrib/less/ttyin.c         |    6 +-
 contrib/less/ubin.uni        |    2 +-
 contrib/less/version.c       |   21 +-
 contrib/less/wide.uni        |   23 +-
 contrib/less/xbuf.c          |   12 +-
 contrib/less/xbuf.h          |   11 +-
 usr.bin/less/defines.h       |  116 ++--
 64 files changed, 2852 insertions(+), 1451 deletions(-)

diff --git a/contrib/less/LICENSE b/contrib/less/LICENSE
index b9b72a3d088b..313cebd4f66f 100644
--- a/contrib/less/LICENSE
+++ b/contrib/less/LICENSE
@@ -2,7 +2,7 @@
                           ------------
 
 Less
-Copyright (C) 1984-2025  Mark Nudelman
+Copyright (C) 1984-2026  Mark Nudelman
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
diff --git a/contrib/less/NEWS b/contrib/less/NEWS
index 442fe21e406a..0f767aaeb059 100644
--- a/contrib/less/NEWS
+++ b/contrib/less/NEWS
@@ -9,6 +9,89 @@
   Report bugs, suggestions or comments at 
   https://github.com/gwsw/less/issues.
 
+======================================================================
+
+	Major changes between "less" versions 691 and 692
+
+* Revert HOME key to scroll to beginning of file and END key
+  to scroll to end of file (github #658).
+
+* Configure tty to leave CR and NL unmodified (github #703).
+
+* Add commands to lesskey parser (forw-bell-hilite, goto-pos and osc8-jump).
+
+* Add key sequences to lesskey parser (\kE, \kF, \kH, \kI, \kM, and \kS).
+
+* Fix bug using negative value with -z option (github #709).
+
+* Fix bug handling empty terminfo capabilties (github #710).
+
+* Fix memory leak in setupterm (github #707).
+
+* Make lesstest ignore system locale (nl_langinfo) (github #708).
+
+======================================================================
+
+	Major changes between "less" versions 685 and 691
+
+* Add --autosave option (github #678).
+
+* Add ESC-f command (github #680).
+
+* Add column number to long prompt and = message.
+
+* Add prompt prototype sequences %C, %W, %Q and ?Q (github #685).
+
+* Map keypad keys, and use terminfo rather than termcap since keypad
+  definitions don't exist in termcap (github #650).
+
+* Change HOME key to scroll fully left and END key to scroll fully right.
+  Add shift-HOME and ctrl-HOME to scroll left and jump to top, and
+  add shift-END and ctrl-END to scroll right and jump to end (github #658).
+
+* Add LESSNOCONFIG environment variable.
+
+* Add --without-termlib to configure (github #701).
+
+* When setting line number colors (-DN), don't force bold attribute.
+  To set bold, you must append "d" or "*" to the color string (github #684).
+
+* While waiting for file data, only ^C or ^X will interrupt, not any command.
+  This reverts to behavior that existed before less-670 (github #700).
+
+* When --save-marks is not used, retain any marks saved in the history file
+  (github #662).
+
+* Defer sending the terminal init string until the first char is read
+  from the input file (github #682).
+
+* Make SIGHUP do an orderly exit like SIGTERM.
+
+* Implement modeline handling in Windows build.
+
+* Fix bugs and improve behavior of screen resize on Windows.
+
+* Fix bug when entering search modifier key at start of non-empty 
+  search string (github #668).
+
+* Fix bug repainting screen with --form-feed (github #672).
+
+* Fix bugs passing invalid negative values to some command line
+  options (github #675).
+
+* Fix incorrect display of Lit indicator (github #670).
+
+* Fix incorrect display when returning to a mark after resizeing window
+  (github #681).
+
+* Fix bug using --pattern with --incsearch (github #696).
+
+* Disallow mouse click to open OSC8 link in SECURE mode (github #676).
+
+* Add SECURE_COMPILE environment variable for Windows builds.
+
+* Update Unicode tables.
+
 ======================================================================
 
 	Major changes between "less" versions 679 and 685
diff --git a/contrib/less/README b/contrib/less/README
index 4bfdc5e5a67f..a6954eb67c1e 100644
--- a/contrib/less/README
+++ b/contrib/less/README
@@ -84,7 +84,7 @@ INSTALLATION (Unix & Linux systems only):
    Makefile now.  Take particular notice of the list of "terminal" 
    libraries in the LIBS definition in the Makefile; these may need 
    to be edited.  The terminal libraries will be some subset of
-       -lncurses  -lcurses  -ltermcap  -ltermlib
+    -ltinfo -ltinfow -lxcurses -lncursesw -lncurses -lcurses -ltermcap -ltermlib
 
    If you wish, you may edit defines.h to remove some optional features.
    If you choose not to include some features in your version, you may
@@ -117,6 +117,29 @@ programmers", not "persons who attempt to circumvent computer security".)
 
 
 
+=======================================================================
+INSTALLATION (Windows-95, Windows-98 and Windows-NT systems only,
+              with Microsoft Visual C++, mingw, or Borland C)
+
+1. Move the distributed source to its own directory.
+
+2. If you wish, you may edit defines.wn to remove some optional features.
+   If you choose not to include some features in your version, you may
+   wish to edit the manual page less.man and the help page help.c
+   to remove the descriptions of the features which you are removing.
+
+3. If you are using Microsoft Visual C++, run "nmake -f Makefile.wnm".
+   If you are using mingw, run "make -f Makefile.wng".
+   If you are using Borland C, run "make -f Makefile.wnb".
+
+   If the environment variable SECURE_COMPILE is to 1 during the make,
+   a "secure" version of less is built, with some features disabled.
+
+4. If the make succeeds, it will generate the programs "less.exe" and
+   "lesskey.exe" in your current directory.  Test the generated programs.
+
+
+
 =======================================================================
 INSTALLATION (MS-DOS systems only,
               with Microsoft C, Borland C, or DJGPP)
@@ -156,34 +179,6 @@ INSTALLATION (MS-DOS systems only,
 
 
 
-=======================================================================
-INSTALLATION (Windows-95, Windows-98 and Windows-NT systems only,
-              with Borland C or Microsoft Visual C++)
-
-1. Move the distributed source to its own directory.
-
-2. If you are using Borland C, rename Makefile.wnb to Makefile.
-   If you are using Microsoft Visual C++, rename Makefile.wnm to Makefile.
-
-3. Check the Makefile to make sure the definitions look ok.
-
-4. If you wish, you may edit defines.wn to remove some optional features.
-   If you choose not to include some features in your version, you may
-   wish to edit the manual page less.man and the help page help.c
-   to remove the descriptions of the features which you are removing.
-
-5. Type "make" and watch the fun.
-
-6. If the make succeeds, it will generate the programs "less.exe" and
-   "lesskey.exe" in your current directory.  Test the generated programs.
-
-7. When satisfied that it works, if you wish to install it
-   in a public place, type "make install".
-   See step 6 of the Unix installation instructions for details
-   on how to change the default installation directories.
-
-
-
 =======================================================================
 INSTALLATION (OS/2 systems only,
               with EMX C)
@@ -245,10 +240,3 @@ INSTALLATION (OS-9 systems only,
    See step 6 of the Unix installation instructions for details
    on how to change the default installation directories.
 
-=======================================================================
-ACKNOWLEDGMENTS:
-  Some versions of the less distribution are packaged using 
-  Info-ZIP's compression utility.
-  Info-ZIP's software is free and can be obtained as source 
-  code or executables from various anonymous-ftp sites,
-  including ftp.uu.net:/pub/archiving/zip.
diff --git a/contrib/less/brac.c b/contrib/less/brac.c
index 36f31d0316f4..b3b74e07d18a 100644
--- a/contrib/less/brac.c
+++ b/contrib/less/brac.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1984-2025  Mark Nudelman
+ * Copyright (C) 1984-2026  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.
diff --git a/contrib/less/ch.c b/contrib/less/ch.c
index fb7572e7f88a..47d31ecffadd 100644
--- a/contrib/less/ch.c
+++ b/contrib/less/ch.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1984-2025  Mark Nudelman
+ * Copyright (C) 1984-2026  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.
@@ -22,7 +22,7 @@
 
 typedef POSITION BLOCKNUM;
 
-public int ignore_eoi;
+public lbool ignore_eoi = FALSE;
 
 /*
  * Pool of buffers holding the most recently used blocks of the input file.
@@ -883,13 +883,13 @@ public void ch_init(int f, int flags, ssize_t nread)
 	 */
 	ch_fsize = (flags & CH_HELPFILE) ? size_helpdata : filesize(ch_file);
 
-	/*
-	 * This is a kludge to workaround a Linux kernel bug: files in some
-	 * pseudo filesystems like /proc and tracefs have a size of 0 according
-	 * to fstat() but have readable data.
-	 */
 	if (ch_fsize == 0 && nread > 0)
 	{
+		/*
+		 * This is a kludge to workaround a Linux kernel bug: files in some
+		 * pseudo filesystems like /proc and tracefs have a size of 0 according
+		 * to fstat() but have readable data.
+		 */
 		ch_flags |= CH_NOTRUSTSIZE;
 	}
 
diff --git a/contrib/less/charset.c b/contrib/less/charset.c
index 0f62739bc88d..74159404148b 100644
--- a/contrib/less/charset.c
+++ b/contrib/less/charset.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1984-2025  Mark Nudelman
+ * Copyright (C) 1984-2026  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.
@@ -202,20 +202,20 @@ static void ichardef_utf(constant char *s)
 			switch (*s++)
 			{
 			case 'b':
-				xbuf_add_data(&user_ubin_array, (unsigned char *) &range, sizeof(range));
+				xbuf_add_data(&user_ubin_array, &range, sizeof(range));
 				break;
 			case 'c':
-				xbuf_add_data(&user_compose_array, (unsigned char *) &range, sizeof(range));
+				xbuf_add_data(&user_compose_array, &range, sizeof(range));
 				break;
 			case 'd':
-				xbuf_add_data(&user_omit_array, (unsigned char *) &range, sizeof(range));
+				xbuf_add_data(&user_omit_array, &range, sizeof(range));
 				break;
 			case 'w':
-				xbuf_add_data(&user_wide_array, (unsigned char *) &range, sizeof(range));
-				xbuf_add_data(&user_prt_array, (unsigned char *) &range, sizeof(range));
+				xbuf_add_data(&user_wide_array, &range, sizeof(range));
+				xbuf_add_data(&user_prt_array, &range, sizeof(range));
 				break;
 			case 'p': case '.':
-				xbuf_add_data(&user_prt_array, (unsigned char *) &range, sizeof(range));
+				xbuf_add_data(&user_prt_array, &range, sizeof(range));
 				break;
 			case '\0':
 				s--;
@@ -429,13 +429,21 @@ static void set_charset(void)
 	/*
 	 * Try using the codeset name as the charset name.
 	 */
-	s = nl_langinfo(CODESET);
-	if (icharset(s, 1))
-		return;
+#if LESSTEST
+	/*
+	 * Don't check nl_langinfo in lesstest mode; charset should come
+	 * only from environment variables, not from the system locale.
+	 */
+	if (0) /* {{ unfortunately it's too early to use is_lesstest }} */
+#endif
+	{
+		s = nl_langinfo(CODESET);
+		if (icharset(s, 1))
+			return;
+	}
 #endif
 #endif
 
-#if HAVE_STRSTR
 	/*
 	 * Check whether LC_ALL, LC_CTYPE or LANG look like UTF-8 is used.
 	 */
@@ -448,7 +456,6 @@ static void set_charset(void)
 			if (icharset("utf-8", 1))
 				return;
 	}
-#endif
 
 #if HAVE_LOCALE
 	/*
diff --git a/contrib/less/charset.h b/contrib/less/charset.h
index 4acf494b4ed5..cf2e02547cb5 100644
--- a/contrib/less/charset.h
+++ b/contrib/less/charset.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1984-2025  Mark Nudelman
+ * Copyright (C) 1984-2026  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.
diff --git a/contrib/less/cmd.h b/contrib/less/cmd.h
index 07c57b111aee..945f99719d0c 100644
--- a/contrib/less/cmd.h
+++ b/contrib/less/cmd.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1984-2025  Mark Nudelman
+ * Copyright (C) 1984-2026  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.
@@ -86,6 +86,7 @@
 #define A_OSC8_JUMP            74
 #define A_START_PASTE          75 /* must not overlap EC_* */
 #define A_END_PASTE            76 /* must not overlap EC_* */
+#define A_F_FOREVER_BELL       77
 
 /* These values must not conflict with any A_* or EC_* value. */
 #define A_INVALID              100
@@ -155,4 +156,27 @@
 #define SK_BACKTAB             15
 #define SK_CTL_BACKSPACE       16
 #define SK_BACKSPACE           17
+#define SK_PAD_U               18
+#define SK_PAD_D               19
+#define SK_PAD_R               20
+#define SK_PAD_L               21
+#define SK_PAD_UR              22
+#define SK_PAD_UL              23
+#define SK_PAD_DR              24
+#define SK_PAD_DL              25
+#define SK_PAD_CENTER          26
+#define SK_PAD_STAR            27
+#define SK_PAD_SLASH           28
+#define SK_PAD_DASH            29
+#define SK_PAD_PLUS            30
+#define SK_PAD_DOT             31
+#define SK_PAD_COMMA           32
+#define SK_PAD_ZERO            33
+#define SK_SHIFT_HOME          34
+#define SK_SHIFT_END           35
+#define SK_CTL_HOME            36
+#define SK_CTL_END             37
+#define SK_SHIFT_LEFT_ARROW    38
+#define SK_SHIFT_RIGHT_ARROW   39
+
 #define SK_CONTROL_K           40
diff --git a/contrib/less/cmdbuf.c b/contrib/less/cmdbuf.c
index f2963cf4c9da..1c3b3d461ad9 100644
--- a/contrib/less/cmdbuf.c
+++ b/contrib/less/cmdbuf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1984-2025  Mark Nudelman
+ * Copyright (C) 1984-2026  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.
@@ -23,7 +23,7 @@
 extern int sc_width;
 extern int utf_mode;
 extern int no_hist_dups;
-extern int marks_modified;
+extern lbool marks_modified;
 extern int no_paste;
 public lbool pasting = FALSE;
 
@@ -35,6 +35,9 @@ static int cmd_offset;           /* Index into cmdbuf of first displayed char */
 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 LESS_INSERT_MODE
+static lbool insert_mode = TRUE;
+#endif
 
 static int cmd_complete(int action);
 /*
@@ -189,7 +192,7 @@ public int len_cmdbuf(void)
  */
 public lbool cmdbuf_empty(void)
 {
-	return cp == cmdbuf && cmd_mbc_buf_len == 0;
+	return cmdbuf[0] == '\0' && cmd_mbc_buf_len == 0;
 }
 
 /*
@@ -454,39 +457,6 @@ static int cmd_left(void)
 	return (CC_OK);
 }
 
-/*
- * Insert a char into the command buffer, at the current position.
- */
-static int cmd_ichar(constant char *cs, size_t clen)
-{
-	char *s;
-	
-	if (strlen(cmdbuf) + clen >= sizeof(cmdbuf)-1)
-	{
-		/* No room in the command buffer for another char. */
-		bell();
-		return (CC_ERROR);
-	}
-		
-	/*
-	 * Make room for the new character (shift the tail of the buffer right).
-	 */
-	for (s = &cmdbuf[strlen(cmdbuf)];  s >= cp;  s--)
-		s[clen] = s[0];
-	/*
-	 * Insert the character into the buffer.
-	 */
-	for (s = cp;  s < cp + clen;  s++)
-		*s = *cs++;
-	/*
-	 * Reprint the tail of the line from the inserted char.
-	 */
-	have_updown_match = FALSE;
-	cmd_repaint(cp);
-	cmd_right();
-	return (CC_OK);
-}
-
 /*
  * Backspace in the command buffer.
  * Delete the char to the left of the cursor.
@@ -502,7 +472,7 @@ static int cmd_erase(void)
 		 * Backspace past beginning of the buffer:
 		 * this usually means abort the command.
 		 */
-		return (CC_QUIT);
+		return CC_QUIT;
 	}
 	/*
 	 * Move cursor left (to the char being erased).
@@ -532,7 +502,7 @@ static int cmd_erase(void)
 	 * to abort the current command, if CF_QUIT_ON_ERASE is set.
 	 */
 	if ((curr_cmdflags & CF_QUIT_ON_ERASE) && cp == cmdbuf && *cp == '\0')
-		return (CC_QUIT);
+		return CC_QUIT;
 	return (CC_OK);
 }
 
@@ -554,6 +524,43 @@ static int cmd_delete(void)
 	return (CC_OK);
 }
 
+/*
+ * Insert a char into the command buffer, at the current position.
+ */
+static int cmd_ichar(constant char *cs, size_t clen)
+{
+	char *s;
+	
+	if (strlen(cmdbuf) + clen >= sizeof(cmdbuf)-1)
+	{
+		/* No room in the command buffer for another char. */
+		lbell();
+		return (CC_ERROR);
+	}
+		
+#if LESS_INSERT_MODE
+	if (!insert_mode)
+		cmd_delete();
+#endif
+	/*
+	 * Make room for the new character (shift the tail of the buffer right).
+	 */
+	for (s = &cmdbuf[strlen(cmdbuf)];  s >= cp;  s--)
+		s[clen] = s[0];
+	/*
+	 * Insert the character into the buffer.
+	 */
+	for (s = cp;  s < cp + clen;  s++)
+		*s = *cs++;
+	/*
+	 * Reprint the tail of the line from the inserted char.
+	 */
+	have_updown_match = FALSE;
+	cmd_repaint(cp);
+	cmd_right();
+	return (CC_OK);
+}
+
 /*
  * Delete the "word" to the left of the cursor.
  */
@@ -612,7 +619,7 @@ static int cmd_kill(void)
 	if (cmdbuf[0] == '\0')
 	{
 		/* Buffer is already empty; abort the current command. */
-		return (CC_QUIT);
+		return CC_QUIT;
 	}
 	cmd_offset = 0;
 	cmd_home();
@@ -625,7 +632,7 @@ static int cmd_kill(void)
 	 * to abort the current command, if CF_QUIT_ON_ERASE is set.
 	 */
 	if (curr_cmdflags & CF_QUIT_ON_ERASE)
-		return (CC_QUIT);
+		return CC_QUIT;
 	return (CC_OK);
 }
 
@@ -660,7 +667,7 @@ static int cmd_updown(int action)
 		/*
 		 * The current command has no history list.
 		 */
-		bell();
+		lbell();
 		return (CC_OK);
 	}
 
@@ -705,7 +712,7 @@ static int cmd_updown(int action)
 	/*
 	 * We didn't find a history entry that matches.
 	 */
-	bell();
+	lbell();
 	return (CC_OK);
 }
 
@@ -796,6 +803,15 @@ public void cmd_addhist(struct mlist *mlist, constant char *cmd, lbool modified)
 	 * Thus, an UPARROW will always retrieve the previous command.
 	 */
 	mlist->curr_mp = ml->next;
+	if (modified)
+	{
+		if (mlist == &mlist_search && autosave_action('/'))
+			save_cmdhist();
+#if SHELL_ESCAPE || PIPEC
+		else if (mlist == &mlist_shell && autosave_action('!'))
+			save_cmdhist();
+#endif
+	}
 #endif
 }
 
@@ -904,6 +920,9 @@ static int cmd_edit(char c, lbool stay_in_completion)
 		return (CC_OK);
 	case EC_INSERT:
 		not_in_completion();
+#if LESS_INSERT_MODE
+		insert_mode = !insert_mode;
+#endif
 		return (CC_OK);
 	case EC_BACKSPACE:
 		not_in_completion();
@@ -914,7 +933,7 @@ static int cmd_edit(char c, lbool stay_in_completion)
 	case EC_ABORT:
 		not_in_completion();
 		(void) cmd_kill();
-		return (CC_QUIT);
+		return CC_QUIT;
 	case EC_W_BACKSPACE:
 		not_in_completion();
 		return (cmd_werase());
@@ -950,17 +969,23 @@ static int cmd_istr(constant char *str)
 {
 	constant char *endline = str + strlen(str);
 	constant char *s;
-	int action;
-	
+	int action = CC_OK;
+#if LESS_INSERT_MODE
+	lbool save_insert_mode = insert_mode;
+	insert_mode = TRUE;
+#endif
 	for (s = str;  *s != '\0';  )
 	{
 		constant char *os = s;
 		step_charc(&s, +1, endline);
 		action = cmd_ichar(os, ptr_diff(s, os));
 		if (action != CC_OK)
-			return (action);
+			break;
 	}
-	return (CC_OK);
+#if LESS_INSERT_MODE
+	insert_mode = save_insert_mode;
+#endif
+	return (action);
 }
 
 /*
@@ -1171,7 +1196,7 @@ static int cmd_complete(int action)
 #endif /* TAB_COMPLETE_FILENAME */
 		if (tk_text == NULL)
 		{
-			bell();
+			lbell();
 			return (CC_OK);
 		}
 		if (action == EC_EXPAND)
@@ -1239,7 +1264,7 @@ static int cmd_complete(int action)
 	
 fail:
 	in_completion = FALSE;
-	bell();
+	lbell();
 	return (CC_OK);
 }
 
@@ -1281,7 +1306,7 @@ static int cmd_uchar(char c, size_t *plen)
 			} else
 			{
 				/* UTF8_INVALID or stray UTF8_TRAIL */
-				bell();
+				lbell();
 				return (CC_ERROR);
 			}
 		} else if (IS_UTF8_TRAIL(c))
@@ -1293,14 +1318,14 @@ static int cmd_uchar(char c, size_t *plen)
 			{
 				/* complete, but not well formed (non-shortest form), sequence */
 				cmd_mbc_buf_len = 0;
-				bell();
+				lbell();
 				return (CC_ERROR);
 			}
 		} else
 		{
 			/* Flush incomplete (truncated) sequence.  */
 			cmd_mbc_buf_len = 0;
-			bell();
+			lbell();
 			/* Handle new char.  */
 			goto retry;
 		}
@@ -1388,7 +1413,6 @@ public LINENUM cmd_int(mutable long *frac)
 {
 	constant char *p;
 	LINENUM n = 0;
-	lbool err;
 
 	for (p = cmdbuf;  *p >= '0' && *p <= '9';  p++)
 	{
@@ -1401,8 +1425,8 @@ public LINENUM cmd_int(mutable long *frac)
 	*frac = 0;
 	if (*p++ == '.')
 	{
-		*frac = getfraction(&p, NULL, &err);
-		/* {{ do something if err is set? }} */
+		/* {{ Just ignore error in fractional part. }} */
+		(void) getfraction(&p, frac);
 	}
 	return (n);
 }
@@ -1447,7 +1471,7 @@ static int mlist_size(struct mlist *ml)
 static char * histfile_find(lbool must_exist)
 {
 	constant char *home = lgetenv("HOME");
-	char *name = NULL;
+	char *name;
 
 	/* Try in $XDG_STATE_HOME, then in $HOME/.local/state, then in $XDG_DATA_HOME, then in $HOME. */
 #if OS2
@@ -1738,7 +1762,7 @@ public void save_cmdhist(void)
 	int skip_shell;
 	struct save_ctx ctx;
 	constant char *s;
-	FILE *fout = NULL;
+	FILE *fout;
 	int histsize = 0;
 
 	if (!secure_allow(SF_HISTORY) || !histfile_modified())
diff --git a/contrib/less/command.c b/contrib/less/command.c
index 390385547385..1bb8d006f8ec 100644
--- a/contrib/less/command.c
+++ b/contrib/less/command.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1984-2025  Mark Nudelman
+ * Copyright (C) 1984-2026  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.
@@ -32,7 +32,7 @@ extern int jump_sline;
 extern lbool quitting;
 extern int wscroll;
 extern int top_scroll;
-extern int ignore_eoi;
+extern lbool ignore_eoi;
 extern int hshift;
 extern int bs_mode;
 extern int proc_backspace;
@@ -49,7 +49,6 @@ extern void *ml_examine;
 extern int wheel_lines;
 extern int def_search_type;
 extern lbool search_wrapped;
-extern lbool no_poll;
 extern int no_paste;
 extern lbool pasting;
 extern int no_edit_warn;
@@ -154,7 +153,7 @@ static void start_mca(int action, constant char *prompt, void *mlist, int cmdfla
 	set_mlist(mlist, cmdflags);
 }
 
-public int in_mca(void)
+public lbool in_mca(void)
 {
 	return (mca != 0 && mca != A_PREFIX);
 }
@@ -476,7 +475,7 @@ static int mca_opt_nonfirst_char(char c)
 		}
 	} else if (!ambig)
 	{
-		bell();
+		lbell();
 	}
 	return (MCA_MORE);
 }
@@ -575,7 +574,10 @@ static int mca_search_char(char c)
 	 */
 	if (!cmdbuf_empty() || literal_char)
 	{
+		lbool was_literal_char = literal_char;
 		literal_char = FALSE;
+		if (was_literal_char)
+			mca_search1();
 		return (NO_MCA);
 	}
 
@@ -639,6 +641,17 @@ static int mca_search_char(char c)
 	return (NO_MCA);
 }
 
+/*
+ * Jump back to the starting position of an incremental search.
+ */
+static void jump_search_incr_pos(void)
+{
+	if (search_incr_pos.pos == NULL_POSITION)
+		return;
+	hshift = search_incr_hshift;
+	jump_loc(search_incr_pos.pos, search_incr_pos.ln);
+}
+
 /*
  * Handle a character of a multi-character command.
  */
@@ -772,30 +785,21 @@ static int mca_char(char c)
 			if (*pattern == '\0')
 			{
 				/* User has backspaced to an empty pattern. */
-				undo_search(1);
-				hshift = search_incr_hshift;
-				jump_loc(search_incr_pos.pos, search_incr_pos.ln);
+				undo_search(TRUE);
+				jump_search_incr_pos();
 			} else
 			{
-				/*
-				 * Suppress tty polling while searching.
-				 * This avoids a problem where tty input
-				 * can cause the search to be interrupted.
-				 */
-				no_poll = TRUE;
 				if (search(st | SRCH_INCR, pattern, 1) != 0)
 				{
 					/* No match, invalid pattern, etc. */
-					undo_search(1);
-					hshift = search_incr_hshift;
-					jump_loc(search_incr_pos.pos, search_incr_pos.ln);
+					undo_search(TRUE);
+					jump_search_incr_pos();
 				}
-				no_poll = FALSE;
 			}
 			/* Redraw the search prompt and search string. */
 			if (is_screen_trashed() || !full_screen)
 			{
-				clear();
+				lclear();
 				repaint();
 			}
 			mca_search1();
@@ -851,7 +855,7 @@ static void make_display(void)
 	 * We need to clear and repaint screen before any change.
 	 */
 	if (!full_screen && !(quit_if_one_screen && one_screen))
-		clear();
+		lclear();
 	/*
 	 * If nothing is displayed yet, display starting from initial_scrpos.
 	 */
@@ -864,9 +868,9 @@ static void make_display(void)
 	} else if (is_screen_trashed() || !full_screen)
 	{
 		int save_top_scroll = top_scroll;
-		int save_ignore_eoi = ignore_eoi;
+		lbool save_ignore_eoi = ignore_eoi;
 		top_scroll = 1;
-		ignore_eoi = 0;
+		ignore_eoi = FALSE;
 		if (is_screen_trashed() == 2)
 		{
 			/* Special case used by ignore_eoi: re-open the input file
@@ -1304,29 +1308,31 @@ static void multi_search(constant char *pattern, int n, int silent)
 /*
  * Forward forever, or until a highlighted line appears.
  */
-static int forw_loop(int until_hilite)
+static int forw_loop(int action)
 {
-	POSITION curr_len;
+	POSITION prev_hilite;
 
 	if (ch_getflags() & CH_HELPFILE)
 		return (A_NOACTION);
 
 	cmd_exec();
 	jump_forw_buffered();
-	curr_len = ch_length();
-	highest_hilite = until_hilite ? curr_len : NULL_POSITION;
-	ignore_eoi = 1;
+	highest_hilite = prev_hilite = 0;
+	ignore_eoi = TRUE;
 	while (!sigs)
 	{
-		if (until_hilite && highest_hilite > curr_len)
+		if (action != A_F_FOREVER && highest_hilite > prev_hilite)
 		{
-			bell();
-			break;
+			lbell();
+			if (action == A_F_UNTIL_HILITE)
+				break;
+			prev_hilite = highest_hilite;
 		}
 		make_display();
 		forward(1, FALSE, FALSE, FALSE);
 	}
-	ignore_eoi = 0;
+	highest_hilite = NULL_POSITION;
+	ignore_eoi = FALSE;
 	ch_set_eof();
 
 	/*
@@ -1334,7 +1340,7 @@ static int forw_loop(int until_hilite)
 	 * a non-abort signal (e.g. window-change).  
 	 */
 	if (sigs && !ABORT_SIGS())
-		return (until_hilite ? A_F_UNTIL_HILITE : A_F_FOREVER);
+		return (action);
 
 	return (A_NOACTION);
 }
@@ -1401,7 +1407,6 @@ public void commands(void)
 #endif
 
 	search_type = SRCH_FORW;
-	wscroll = (sc_height + 1) / 2;
 	newaction = A_NOACTION;
 
 	for (;;)
@@ -1507,7 +1512,9 @@ public void commands(void)
 				 * want erase_char/kill_char to be treated
 				 * as line editing characters.
 				 */
-				constant char tbuf[2] = { c, '\0' };
+				char tbuf[2];
+				tbuf[0] = c;
+				tbuf[1] = '\0';
 				action = fcmd_decode(tbuf, &extra);
 			}
 			/*
*** 8507 LINES SKIPPED ***