Commit Graph

154 Commits

Author SHA1 Message Date
Salvatore Sanfilippo
a7b86c1744 Add test framework with VT100 terminal emulator
Implement comprehensive test suite for linenoise:

VT100 Terminal Emulator:
- Column-based UTF-8 representation with display width tracking
- Each screen cell stores complete UTF-8 characters (up to 32 bytes)
- Proper handling of wide characters (emoji, CJK) as 2-column cells
- ZWJ tracking for grapheme cluster storage
- Escape sequence parsing for cursor movement and screen clearing

Test Harness:
- Fork/pipe architecture for testing via LINENOISE_ASSUME_TTY
- Visual rendering to real terminal for debugging failed tests
- Assertion helpers for screen content and cursor position

Test Coverage (72 tests):
- Basic typing and cursor movement
- UTF-8 input and navigation (é, 中, 🎉)
- Emoji cursor movement and deletion
- Grapheme clusters (heart+VS, thumbs up+skin tone, rainbow flag)
- Horizontal scrolling with long lines
- Horizontal scrolling with UTF-8 content
- Multiline mode basics
- Multiline history navigation (regression test)
- Word/line deletion (Ctrl-W, Ctrl-U)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 21:58:30 +01:00
Salvatore Sanfilippo
c12b66d255 Add UTF-8 and grapheme cluster support
Implement comprehensive UTF-8 handling for linenoise:

Core UTF-8 support:
- Proper multi-byte character navigation (left/right arrows)
- Correct backspace deletion for multi-byte characters
- Display width calculation for cursor positioning
- Wide character support (CJK, emoji) as 2-column display

Grapheme cluster support for complex emoji:
- Variation selectors (U+FE0E, U+FE0F) for emoji style
- Skin tone modifiers (U+1F3FB-U+1F3FF)
- Zero Width Joiner (U+200D) sequences like rainbow flag
- Regional indicators for flag emoji
- Combining diacritical marks

Navigation and deletion now treat entire grapheme clusters as single
units. For example, 🏳️‍🌈 (14 bytes, 4 codepoints) is handled as one
character for cursor movement and backspace.

Multiline mode fixes:
- Fix history navigation regression where going from multi-row to
  single-row entries left dirty rows on screen
- Save actual cursor row position (oldrpos) instead of recalculating

Updates to linenoise.c:
- Add helper functions for UTF-8 decoding and grapheme detection
- Rewrite utf8PrevCharLen/utf8NextCharLen for grapheme clusters
- Add utf8CharWidth with proper zero-width character handling
- Add utf8StrWidth with ZWJ sequence support
- Fix refreshMultiLine cursor row tracking

Updates to linenoise.h:
- Add oldrpos field to linenoiseState for multiline cursor tracking

Updates to README:
- Document UTF-8 support for multi-byte characters and emoji
- Update line count from ~850 to ~1100
- Add "Running the tests" section

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 21:58:20 +01:00
Salvatore Sanfilippo
e26268de5e Merge pull request #245 from matthewnourse/make-linenoiseEditFeed-handle-zero-available-bytes
Multiplexing: make lineNoiseEditFeed handle 0 available bytes.
2025-11-27 17:27:46 +01:00
Matthew Nourse
49202848c8 Fit coding style guidelines 2025-11-27 20:47:36 +11:00
Matthew Nourse
cb7ccfbb9f Multiplexing: if lineNoiseEditFeed is called when there are no bytes available on the open input fd then return linenoiseEditMore rather than NULL. 2025-11-27 16:37:26 +11:00
Salvatore Sanfilippo
880b94130f Merge pull request #240 from gtwilliams/patch-1
Fix CVE-2025-9810
2025-09-10 17:27:26 +02:00
Garry T. Williams
f2558e1e58 Fix CVE-2025-9810 2025-09-10 09:48:24 -04:00
Salvatore Sanfilippo
d895173d67 Merge pull request #221 from 9Ajiang/master
advance enableRawMode() before getColumns()
2024-02-23 08:59:30 +01:00
9A
4111f1d6cd advance enableRawMode() before getColumns() 2024-02-23 15:44:25 +08:00
antirez
93b2db9bd4 Multiplexing: documentation improved. 2023-03-27 13:17:49 +02:00
antirez
3476ccc9c7 Multiplexing: README updated. 2023-03-27 10:36:03 +02:00
antirez
8087db33d8 Multiline: just remember last num of rows, not max.
For some reason, the old code was always cleaning the maximum number of
rows used so far while editing in multi line mode. Actually we need to
clean just the number of rows used by the last line. The old behavior
created problems in multiplexing mode, where the line is refreshed at a
different row, if the user used linenoiseHide() / show() in order to
print something. With the new behavior, all looks fine, so far.
2023-03-27 10:07:47 +02:00
antirez
81f44df639 Multiplexing: fix line refresh in completion mode. 2023-03-27 09:36:31 +02:00
antirez
a1d8e181c2 Multiplexing: make completion non-blocking as well. 2023-03-27 09:21:31 +02:00
antirez
65db823f8b Some documentation and comments updates. 2023-03-26 23:27:33 +02:00
antirez
c9d36d0681 Multiplexing: API refactoring, no TTY support. 2023-03-26 22:22:40 +02:00
antirez
dbfe83bb67 Multiplexing: fix refreshMultiLine(). 2023-03-26 16:44:29 +02:00
antirez
622c777f41 Multiplexing: implement example using it. 2023-03-26 16:42:22 +02:00
antirez
c9123ec3c6 Multiplexing: hide/show current line. 2023-03-26 13:23:59 +02:00
antirez
0d66aaca11 Multiplexing: code refactored into calls for each step. 2023-03-26 11:04:28 +02:00
antirez
97d2850af1 Use unsigned int instead of uint like rest of code base. 2020-03-12 15:51:45 +01:00
Salvatore Sanfilippo
4ce393a66b Merge pull request #185 from yossigo/fix-c99-warning
Fix compilation in non C99/C11 mode.
2020-03-12 15:48:04 +01:00
Yossi Gottlieb
8c1c63c5fd Fix compilation in non C99/C11 mode. 2020-03-12 14:48:36 +02:00
Salvatore Sanfilippo
fc9667a81d Merge pull request #183 from lifubang/fixmasking
fix masking input when there is no hintsCallback
2020-03-05 10:44:35 +01:00
lifubang
ec5e4e8716 fix masking input when there is no hintsCallback
Signed-off-by: lifubang <lifubang@acmcoder.com>
2020-03-03 11:51:08 +08:00
antirez
4261898b11 A few improvements to mask mode. 2020-03-02 17:06:38 +01:00
Salvatore Sanfilippo
f31e883a08 Merge pull request #182 from lifubang/masking
add mask input mode
2020-03-02 16:56:27 +01:00
lifubang
514b09cd35 add mask input mode
Signed-off-by: lifubang <lifubang@acmcoder.com>
2020-03-01 18:32:11 +08:00
Salvatore Sanfilippo
4a961c0108 Merge pull request #151 from hoelzro/master
Set seq to empty string if color/bold not used
2018-07-18 18:29:05 +02:00
Salvatore Sanfilippo
cc2ea638ee Merge pull request #152 from fbrusch/master
Update README.markdown
2018-07-18 18:27:56 +02:00
fbrusch
cc53ed4bb0 Update README.markdown
Fix little typo
2018-04-22 12:43:43 +02:00
Rob Hoelz
b12f6ba9cb Set seq to empty string if color/bold not used
Otherwise the subsequent abAppend will concatenate whatever junk data
is in seq to ab
2018-02-15 22:38:41 -06:00
antirez
2105ce4458 README: add related projects section. 2017-06-20 11:30:07 +02:00
antirez
c894b9e59f Fix insecure history file creation.
See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=832460.

This patch was kindly contributed by Chris Lamb (@lamby).
2016-07-29 11:25:35 +02:00
antirez
2eb4956846 Clear hints after newline. 2016-04-13 12:19:04 +02:00
antirez
a64257a8d2 Hints: when only bold is set, use color 37 (white). 2016-04-12 18:44:46 +02:00
antirez
24c52baad6 Linenoise API documented. 2016-04-12 18:39:43 +02:00
antirez
24e401c202 Use sane defaults for hints color and bold. 2016-04-12 18:35:12 +02:00
antirez
ae5f793ec0 linenoiseFree() API introduced. 2016-04-12 18:08:33 +02:00
antirez
12a8680d8a Hints WIP 2016-04-12 17:59:41 +02:00
antirez
d97e7665a8 Copyright info updated. 2016-04-06 13:40:15 +02:00
antirez
94d9ddb256 4096 bytes line limit removed when STDIN is not a tty. 2016-04-06 13:39:09 +02:00
antirez
027dbcef5d Reported to work with Emacs comint mode. 2015-07-13 16:04:24 +02:00
antirez
80fd0569d1 Version 1.0
Linenoise is used in multiple projects for enough time, let's tag this
commit with a version number as requested into issue #88, so that we
have an initial reference.

Given the nature of the library, the version was also added in the
linenoise C and header file as well so that it is easy to realize for
people having a copy embedded somewhere if they are using the latest
version.
1.0
2015-04-13 09:38:43 +02:00
antirez
cf1bdf5f89 License file added.
However the files linenose.c and linenose.h already had inline licenses.
2014-10-07 15:23:53 +02:00
antirez
c1c5a026d0 Move to end before return when in multi-line mode.
This makes sure that if we are editing in multi-line mode a line that
actually spawns across multiple lines, the next output performed by the
application using linenoise will not overwrite the edited line.
2014-09-03 11:49:43 +02:00
antirez
01e723a095 Replace ESC 999D with CR.
OSX default Terminal app does not handle 999D well, the cursor will wrap
back to the previous row in the last colum, instead of ignoring the
sequence if the cursor is already at the left edge.

In order to avoid reintroducing the nG sequence that is not compatible
with base VT100 emulation and ANSI.SYS, we use CR that should be
hopefully widely supported.
2014-09-03 11:38:19 +02:00
antirez
c84d0a02ce Don't emit ESC [ n C with n=0.
This fixes a bug introduced with ANSI.SYS compatibility.
When we want to move at a specific column, we need to emit the sequence
to move the cursor to the right (after we moved 999 positions to the left)
only if we want to actually move right at least 1 position, since a
count of zero will still move the cursor one position to the right.
2014-09-03 10:11:31 +02:00
antirez
471e754601 Better specify the set of escapes used. 2014-09-03 09:51:29 +02:00
antirez
0a745fca68 Avoid CHA sequence for ANSI.SYS compatibility.
Github user @welash proposed a change in issue #73 in order to improve
the linenoise compatibility with older terminal emulators only able to
deal with a subset of ANSI sequences, notably ANSI.SYS and VT100
terminals strictly able to handle the original set of VT100 escape
sequences.

In order to improve the compatibility, the CHA sequence was removed and
translated to move 999 positions to the left, then move on the right
for the desired number of positions. The CHA sequence was apparently
added only with VT220, that's why it is not available everywhere.

This commit features almost exactly the change proposed in issue #73
with a small fix for a bug in multi-line editing mode introduced by the
patch.
2014-09-03 09:30:32 +02:00