Compare commits

...

71 Commits

Author SHA1 Message Date
Bram Moolenaar
26e8558e74 patch 8.0.0717: terminal feature precence unclear
Problem:    Terminal feature not included in :version output.
Solution:   Add +terminal or -terminal.
2017-07-15 20:05:54 +02:00
Bram Moolenaar
c4da113ef9 patch 8.0.0716: not easy to start Vim cleanly
Problem:    Not easy to start Vim cleanly without changing the viminfo file.
            Not possible to know whether the -i command line flag was used.
Solution:   Add the --clean command line argument.  Add the 'viminfofile'
            option.  Add "-u DEFAULTS".
2017-07-15 19:39:43 +02:00
Bram Moolenaar
a92522fbf3 patch 8.0.0714: when a timer causes a command line redraw " goes missing
Problem:    When a timer causes a command line redraw the " that is displayed
            for CTRL-R goes missing.
Solution:   Remember an extra character to display.
2017-07-15 15:21:38 +02:00
Bram Moolenaar
0daf843b4c patch 8.0.0713: 'termkey' option not fully implemented
Problem:    'termkey' option not fully implemented.
Solution:   Add initialisation.
2017-07-15 15:16:40 +02:00
Bram Moolenaar
1b0675caec patch 8.0.0712: the terminal implementation is incomplete
Problem:    The terminal implementation is incomplete.
Solution:   Add the 'termkey' option.
2017-07-15 14:04:01 +02:00
Bram Moolenaar
74675a666b Updated runtime files and translations. 2017-07-15 13:53:23 +02:00
Bram Moolenaar
85dad2c815 patch 8.0.0711: cannot build without the wildmenu feature
Problem:    Cannot build without the wildmenu feature.
Solution:   Add #ifdef
2017-07-12 21:12:43 +02:00
Bram Moolenaar
8603356bf4 patch 8.0.0710: a job that writes to a buffer clears completion
Problem:    A job that writes to a buffer clears command line completion.
            (Ramel Eshed)
Solution:   Do not redraw while showing the completion menu.
2017-07-12 20:24:41 +02:00
Bram Moolenaar
8327d1df17 patch 8.0.0709: libvterm cannot use vsnprintf()
Problem:    Libvterm cannot use vsnprintf(), it does not exist in C90.
Solution:   Use vim_vsnprintf() instead.
2017-07-11 22:34:51 +02:00
Bram Moolenaar
292eff0c5a patch 8.0.0708: some tests are old style
Problem:    Some tests are old style.
Solution:   Change a few tests from old style to new style. (pschuh,
            closes #1813)
2017-07-11 21:46:28 +02:00
Bram Moolenaar
f1d13478e3 patch 8.0.0707: freeing wrong memory with certain autocommands
Problem:    Freeing wrong memory when manipulating buffers in autocommands.
            (James McCoy)
Solution:   Also set the w_s pointer if w_buffer was NULL.
2017-07-11 18:28:46 +02:00
Bram Moolenaar
5a15b6aa0a patch 8.0.0706: crash when cancelling the cmdline window in Ex mode
Problem:    Crash when cancelling the cmdline window in Ex mode. (James McCoy)
Solution:   Do not set cmdbuff to NULL, make it empty.
2017-07-11 15:11:57 +02:00
Bram Moolenaar
cae24be4a8 patch 8.0.0705: crash when there is an error in a timer callback
Problem:    Crash when there is an error in a timer callback. (Aron Griffis,
            Ozaki Kiichi)
Solution:   Check did_throw before discarding an exception.  NULLify
            current_exception when no longer valid.
2017-07-10 22:12:10 +02:00
Bram Moolenaar
163095f088 patch 8.0.0704: problems with autocommands when opening help
Problem:    Problems with autocommands when opening help.
Solution:   Avoid using invalid "varp" value.  Allow using :wincmd if buffer
            is locked. (closes #1806, closes #1804)
2017-07-09 15:41:53 +02:00
Bram Moolenaar
faf29d7f91 patch 8.0.0703: illegal memory access with empty :doau command
Problem:    Illegal memory access with empty :doau command.
Solution:   Check the event for being out of range. (James McCoy)
2017-07-09 11:07:16 +02:00
Bram Moolenaar
c577d813b7 patch 8.0.0702: an error in a timer can make Vim unusable
Problem:    An error in a timer can make Vim unusable.
Solution:   Don't set the error flag or exception from a timer.  Stop a timer
            if it causes an error 3 out of 3 times.  Discard an exception
            caused inside a timer.
2017-07-08 22:37:34 +02:00
Bram Moolenaar
11e79bb04e patch 8.0.0701: system test failing when using X11 forwarding
Problem:    System test failing when using X11 forwarding.
Solution:   Set $XAUTHORITY before changing $HOME. (closes #1812)
            Also use a better check for the exit value.
2017-07-08 17:03:21 +02:00
Bram Moolenaar
0ea5070d79 patch 8.0.0700: segfault with QuitPre autocommand closes the window
Problem:    Segfault with QuitPre autocommand closes the window. (Marek)
Solution:   Check that the window pointer is still valid. (Christian Brabandt,
            closes #1817)
2017-07-08 14:44:50 +02:00
Bram Moolenaar
710b4a1646 patch 8.0.0699: checksum tests are not actually run
Problem:    Checksum tests are not actually run.
Solution:   Add the tests to the list. (Dominique Pelle, closes #1819)
2017-07-08 14:29:19 +02:00
Bram Moolenaar
c4f833808a patch 8.0.0698: crash on exit when using Python function in timer.
Problem:    When a timer uses ":pyeval" or another Python command and it
            happens to be triggered while exiting a Crash may happen.
            (Ricky Zhou)
Solution:   Avoid running a Python command after python_end() was called.
            Do not trigger timers while exiting.  (closes #1824)
2017-07-07 14:50:44 +02:00
Bram Moolenaar
8858498516 patch 8.0.0697: recorded key sequences may become invalid
Problem:    Recorded key sequences may become invalid.
Solution:   Add back KE_SNIFF removed in 7.4.1433. Use fixed numbers for the
            key_extra enum.
2017-07-07 13:32:14 +02:00
Bram Moolenaar
cce1cf12eb patch 8.0.0696: .inc files missing in git
Problem:    The .inc files are missing in git. (Nazri Ramliy)
Solution:   Remove the .inc line from .gitignore.
2017-07-07 13:04:16 +02:00
Bram Moolenaar
e5ae108ab8 patch 8.0.0695: missing dependencies breaks parallel make
Problem:    Missing dependencies breaks parallel make.
Solution:   Add dependencies for terminal.o.
2017-07-07 12:42:40 +02:00
Bram Moolenaar
a34293ae0a patch 8.0.0694: building in shadow directory does not work
Problem:    Building in shadow directory does not work.  Running Vim fails.
Solution:   Add the new libvterm directory.  Add missing change in command
            list.
2017-07-07 12:22:55 +02:00
Bram Moolenaar
e4f25e4a8d patch 8.0.0693: no terminal emulator support
Problem:    No terminal emulator support.  Cannot properly run commands in the
            GUI.  Cannot run a job interactively with an ssh connection.
Solution:   Very early implementation of the :terminal command.  Includes
            libvterm converted to ANSI C.  Many parts still missing.
2017-07-07 11:54:15 +02:00
Bram Moolenaar
da5116da45 patch 8.0.0692: CTRL-G with 'incsearch' and ? goes in the wrong direction
Problem:    Using CTRL-G with 'incsearch' and ? goes in the wrong direction.
            (Ramel Eshed)
Solution:   Adjust search_start. (Christian Brabandt)
2017-07-01 23:11:17 +02:00
Bram Moolenaar
a83fe75ca7 patch 8.0.0691: compiler warning without the linebreak feature
Problem:    Compiler warning without the linebreak feature.
Solution:   Add #ifdef. (John Marriott)
2017-06-29 22:33:13 +02:00
Bram Moolenaar
c2226845eb patch 8.0.0690: compiler warning on non-Unix system
Problem:    Compiler warning on non-Unix system.
Solution:   Add #ifdef. (John Marriott)
2017-06-29 22:27:24 +02:00
Bram Moolenaar
a693d0584b patch 8.0.0689: ~ character not escaped when extending search pattern
Problem:    The ~ character is not escaped when adding to the search pattern
            with CTRL-L. (Ramel Eshed)
Solution:   Escape the character. (Christian Brabandt)
2017-06-29 22:23:06 +02:00
Bram Moolenaar
9c4fefffb6 patch 8.0.0688: cannot resize the window in a FileType autocommand
Problem:    Cannot resize the window in a FileType autocommand. (Ingo Karkat)
Solution:   Add the CMDWIN flag to :resize. (test by Ingo Karkat,
            closes #1804)
2017-06-28 22:26:54 +02:00
Bram Moolenaar
86f100dc09 patch 8.0.0687: minor issues related to quickfix
Problem:    Minor issues related to quickfix.
Solution:   Set the proper return status for all cases in setqflist() and at
            test cases for this.  Move the "adding" flag outside of
            FEAT_WINDOWS. Minor update to the setqflist() help text. (Yegappan
            Lakshmanan)
2017-06-28 21:26:27 +02:00
Bram Moolenaar
9f5f7bf4d5 patch 8.0.0686: extra redraw when using CTRL-L in second window
Problem:    When typing CTRL-L in a window that's not the first one, another
            redraw will happen later. (Christian Brabandt)
Solution:   Reset must_redraw after calling screenclear().
2017-06-28 20:45:26 +02:00
Bram Moolenaar
e6bf655bc4 patch 8.0.0685: when conversion fails written file may be truncated
Problem:    When making backups is disabled and conversion with iconv fails
            the written file is truncated. (Luo Chen)
Solution:   First try converting the file and write the file only when it did
            not fail. (partly by Christian Brabandt)
2017-06-27 22:11:51 +02:00
Bram Moolenaar
28b238225a patch 8.0.0684: old style tests are not nice
Problem:    Old style tests are not nice.
Solution:   Turn two tests into new style. (pschuh, closes #1797)
2017-06-27 18:29:17 +02:00
Bram Moolenaar
2e147caa14 patch 8.0.0683: visual bell flashes too quickly
Problem:    When using a visual bell there is no delay, causing the flash to
            be very short, possibly unnoticeable.  Also, the flash and the
            beep can lockup the UI when repeated often.
Solution:   Do the delay in Vim or flush the output before the delay. Limit the
            bell to once per half a second. (Ozaki Kiichi, closes #1789)
2017-06-27 17:09:37 +02:00
Bram Moolenaar
0b2eef24bc patch 8.0.0682: no test for synIDtrans()
Problem:    No test for synIDtrans().
Solution:   Add a test. (Dominique Pelle, closes #1796)
2017-06-27 15:43:49 +02:00
Bram Moolenaar
18d90b95c4 patch 8.0.0681: unnamed register only contains the last deleted text
Problem:    Unnamed register only contains the last deleted text when
            appending deleted text to a register. (Wolfgang Jeltsch)
Solution:   Only set y_previous when not using y_append. (Christian Brabandt)
2017-06-27 15:39:14 +02:00
Bram Moolenaar
07ecfa64a1 patch 8.0.0680: plugins in start packages are sourced twice
Problem:    Plugins in start packages are sourced twice. (mseplowitz)
Solution:   Use the unmodified runtime path when loading plugins (test by Ingo
            Karkat, closes #1801)
2017-06-27 14:43:55 +02:00
Bram Moolenaar
41cc038ff8 patch 8.0.0679: using freed memory
Problem:    Using freed memory.
Solution:   Get the parent frame pointer earlier.
2017-06-26 09:59:35 +02:00
Bram Moolenaar
8eeeba8c02 patch 8.0.0678: closing a window does not trigger resizing
Problem:    When 'equalalways' is set and closing a window in a separate
            frame, not all window sizes are adjusted. (Glacambre)
Solution:   Resize all windows if the new current window is not in the same
            frame as the closed window. (closes #1707)
2017-06-25 22:45:39 +02:00
Bram Moolenaar
1814183b86 patch 8.0.0677: setting 'filetype' may switch buffers
Problem:    Setting 'filetype' internally may cause the current buffer and
            window to change unexpectedly.
Solution:   Set curbuf_lock. (closes #1734)
2017-06-25 21:17:25 +02:00
Bram Moolenaar
182a17b1e8 patch 8.0.0676: crash when closing quickfix window in autocmd
Problem:    Crash when closing the quickfix window in a FileType autocommand
            that triggers when the quickfix window is opened.
Solution:   Save the new value before triggering the OptionSet autocommand.
            Add the "starting" flag to test_override() to make the text work.
2017-06-25 20:57:18 +02:00
Bram Moolenaar
774e5a9673 patch 8.0.0675: 'colorcolumn' has a higher priority than 'hlsearch'
Problem:    'colorcolumn' has a higher priority than 'hlsearch', it should be
            the other way around. (Nazri Ramliy)
Solution:   Change the priorities. (LemonBoy, closes #1794)
2017-06-25 18:03:37 +02:00
Bram Moolenaar
5d7be4f0fa patch 8.0.0674: cannot build with eval but without timers
Problem:    Cannot build with eval but without timers.
Solution:   Add #ifdef (John Marriott)
2017-06-25 13:40:17 +02:00
Bram Moolenaar
ea20de8146 patch 8.0.0673: build failure without conceal feature
Problem:    Build failure without conceal feature.
Solution:   Add #ifdef.
2017-06-24 22:52:24 +02:00
Bram Moolenaar
cc0750dc6e patch 8.0.0672: third item of synconcealed() changes too often
Problem:    Third item of synconcealed() changes too often. (Dominique Pelle)
Solution:   Reset the sequence number at the start of each line.
2017-06-24 22:29:24 +02:00
Bram Moolenaar
4eb6531b03 patch 8.0.0671: hang when typing CTRL-C in confirm() in timer
Problem:    When a function invoked from a timer calls confirm() and the user
            types CTRL-C then Vim hangs.
Solution:   Reset typebuf_was_filled. (Ozaki Kiichi, closes #1791)
2017-06-24 18:49:00 +02:00
Bram Moolenaar
1e8e14552e patch 8.0.0670: can't use input() in a timer callback
Problem:    Can't use input() in a timer callback. (Cosmin Popescu)
Solution:   Reset vgetc_busy and set timer_busy. (Ozaki Kiichi, closes #1790,
            closes #1129)
2017-06-24 16:03:06 +02:00
Bram Moolenaar
24a9e348aa patch 8.0.0669: CTRL-N at start of the buffer does not work correctly
Problem:    In Insert mode, CTRL-N at start of the buffer does not work
            correctly. (zuloloxi)
Solution:   Wrap around the start of the buffer. (Christian Brabandt)
2017-06-24 15:39:07 +02:00
Bram Moolenaar
a1bd86e0f2 patch 8.0.0668: nsis installer script does not work
Problem:    Nsis installer script does not work. (Christian Brabandt)
Solution:   Fix the syntax of /SD.
2017-06-24 15:11:01 +02:00
Bram Moolenaar
53564f7c1a patch 8.0.0667: memory access error when command follows :endfunc
Problem:    Memory access error when command follows :endfunction. (Nikolai
            Pavlov)
Solution:   Make memory handling in :function straightforward. (closes #1793)
2017-06-24 14:48:11 +02:00
Bram Moolenaar
5fe691240b patch 8.0.0666: dead for loop
Problem:    Dead for loop. (Coverity)
Solution:   Remove the for loop.
2017-06-23 23:00:08 +02:00
Bram Moolenaar
090209bfbd patch 8.0.0665: warning for uninitialized variable
Problem:    Warning for uninitialized variable. (Tony Mechelynck)
Solution:   Initialize it.
2017-06-23 22:45:33 +02:00
Bram Moolenaar
6d006f9e95 patch 8.0.0664: mouse does not work in tmux
Problem:    Mouse does not work in tmux. (lilydjwg)
Solution:   Add flag for SGR release being present.
2017-06-23 22:35:34 +02:00
Bram Moolenaar
f8be461d02 patch 8.0.0663: unexpected error message only when 'verbose' is set
Problem:    Giving an error message only when 'verbose' set is unexpected.
Solution:   Give a warning message instead.
2017-06-23 20:52:40 +02:00
Bram Moolenaar
4670490673 patch 8.0.0662: stray FIXME for fixed problem
Problem:    Stray FIXME for fixed problem.
Solution:   Remove the comment. (Dominique Pelle)
2017-06-22 23:03:12 +02:00
Bram Moolenaar
a529ce068b patch 8.0.0661: recognizing urxvt mouse codes does not work well
Problem:    Recognizing urxvt mouse codes does not work well.
Solution:   Recognize "Esc[*M" and "Esc[*m". (Maurice Bos, closes #1486)
2017-06-22 22:37:57 +02:00
Bram Moolenaar
a1fed064d1 patch 8.0.0660: silent install on MS-Windows shows dialog
Problem:    Silent install on MS-Windows does show a dialog.
Solution:   Add /SD to the default choice. (allburov, closes #1772)
2017-06-22 22:05:02 +02:00
Bram Moolenaar
4d785895d1 patch 8.0.0659: no test for conceal mode
Problem:    No test for conceal mode.
Solution:   Add a conceal mode test. (Dominique Pelle, closes #1783)
2017-06-22 22:00:50 +02:00
Bram Moolenaar
d2c061d24c patch 8.0.0658: spell test is old style
Problem:    Spell test is old style.
Solution:   Turn the spell test into a new style test (pschuh, closes #1778)
2017-06-22 21:42:49 +02:00
Bram Moolenaar
6a8958db25 patch 8.0.0657: cannot get and set quickfix list items
Problem:    Cannot get and set quickfix list items.
Solution:   Add the "items" argument to getqflist() and setqflist(). (Yegappan
            Lakshmanan)
2017-06-22 21:33:20 +02:00
Bram Moolenaar
6f9a476b2f patch 8.0.0656: cannot use ! after some user commands
Problem:    Cannot use ! after some user commands.
Solution:   Properly check for existing command. (Higashi Higashi)
2017-06-22 20:39:17 +02:00
Bram Moolenaar
d6abcd154c patch 8.0.0655: not easy to make sure a function does not exist
Problem:    Not easy to make sure a function does not exist.
Solution:   Add ! as an optional argument to :delfunc.
2017-06-22 19:15:24 +02:00
Bram Moolenaar
663bb23316 patch 8.0.0654: no warning for text after :endfunction
Problem:    Text found after :endfunction is silently ignored.
Solution:   Give a warning if 'verbose' is set.  When | or \n are used,
            execute the text as a command.
2017-06-22 19:12:10 +02:00
Bram Moolenaar
c768a208ca patch 8.0.0653: the default highlight for QuickFixLine is not good
Problem:    The default highlight for QuickFixLine does not work for several
            color schemes. (Manas Thakur)
Solution:   Make the default use the old color. (closes #1780)
2017-06-22 16:04:27 +02:00
Bram Moolenaar
383aa84c0d patch 8.0.0652: unicode information is outdated
Problem:    Unicode information is outdated.
Solution:   Update to Unicode 10. (Christian Brabandt)
2017-06-22 15:27:37 +02:00
Bram Moolenaar
157069b04e patch 8.0.0651: build failure without the auto command feature
Problem:    Build failure without the auto command feature.
Solution:   Add #ifdef. (closes #1782)
2017-06-22 14:56:12 +02:00
Bram Moolenaar
868831f122 patch 8.0.0650: for extra help files the filetype is set more than once
Problem:    For extra help files the filetype is set more than once.
Solution:   In *.txt files check that there is no help file modline.
2017-06-22 14:47:22 +02:00
Bram Moolenaar
9049298f8d patch 8.0.0649: when opening a help file the filetype is set several times
Problem:    When opening a help file the filetype is set several times.
Solution:   When setting the filetype to the same value from a modeline, don't
            trigger FileType autocommands.  Don't set the filetype to "help"
            when it's already set correctly.
2017-06-22 14:16:31 +02:00
Bram Moolenaar
fadacf01d0 patch 8.0.0648: possible use of NULL pointer
Problem:    Possible use of NULL pointer if buflist_new() returns NULL.
            (Coverity)
Solution:   Check for NULL pointer in set_bufref().
2017-06-19 20:35:32 +02:00
Bram Moolenaar
06f1ed2f78 patch 8.0.0647: syntax highlighting can make cause a freeze
Problem:    Syntax highlighting can make cause a freeze.
Solution:   Apply 'redrawtime' to syntax highlighting, per window.
2017-06-18 22:41:03 +02:00
222 changed files with 19517 additions and 4691 deletions

View File

@@ -85,6 +85,7 @@ SRC_ALL = \
src/syntax.c \
src/tag.c \
src/term.c \
src/terminal.c \
src/term.h \
src/termlib.c \
src/ui.c \
@@ -187,6 +188,7 @@ SRC_ALL = \
src/proto/syntax.pro \
src/proto/tag.pro \
src/proto/term.pro \
src/proto/terminal.pro \
src/proto/termlib.pro \
src/proto/ui.pro \
src/proto/undo.pro \
@@ -194,6 +196,76 @@ SRC_ALL = \
src/proto/version.pro \
src/proto/winclip.pro \
src/proto/window.pro \
src/libvterm/.bzrignore \
src/libvterm/.gitignore \
src/libvterm/LICENSE \
src/libvterm/Makefile \
src/libvterm/README \
src/libvterm/tbl2inc_c.pl \
src/libvterm/vterm.pc.in \
src/libvterm/bin/unterm.c \
src/libvterm/bin/vterm-ctrl.c \
src/libvterm/bin/vterm-dump.c \
src/libvterm/doc/URLs \
src/libvterm/doc/seqs.txt \
src/libvterm/include/vterm.h \
src/libvterm/include/vterm_keycodes.h \
src/libvterm/src/encoding.c \
src/libvterm/src/encoding/DECdrawing.inc \
src/libvterm/src/encoding/DECdrawing.tbl \
src/libvterm/src/encoding/uk.inc \
src/libvterm/src/encoding/uk.tbl \
src/libvterm/src/keyboard.c \
src/libvterm/src/mouse.c \
src/libvterm/src/parser.c \
src/libvterm/src/pen.c \
src/libvterm/src/rect.h \
src/libvterm/src/screen.c \
src/libvterm/src/state.c \
src/libvterm/src/unicode.c \
src/libvterm/src/utf8.h \
src/libvterm/src/vterm.c \
src/libvterm/src/vterm_internal.h \
src/libvterm/t/02parser.test \
src/libvterm/t/03encoding_utf8.test \
src/libvterm/t/10state_putglyph.test \
src/libvterm/t/11state_movecursor.test \
src/libvterm/t/12state_scroll.test \
src/libvterm/t/13state_edit.test \
src/libvterm/t/14state_encoding.test \
src/libvterm/t/15state_mode.test \
src/libvterm/t/16state_resize.test \
src/libvterm/t/17state_mouse.test \
src/libvterm/t/18state_termprops.test \
src/libvterm/t/20state_wrapping.test \
src/libvterm/t/21state_tabstops.test \
src/libvterm/t/22state_save.test \
src/libvterm/t/25state_input.test \
src/libvterm/t/26state_query.test \
src/libvterm/t/27state_reset.test \
src/libvterm/t/28state_dbl_wh.test \
src/libvterm/t/29state_fallback.test \
src/libvterm/t/30pen.test \
src/libvterm/t/40screen_ascii.test \
src/libvterm/t/41screen_unicode.test \
src/libvterm/t/42screen_damage.test \
src/libvterm/t/43screen_resize.test \
src/libvterm/t/44screen_pen.test \
src/libvterm/t/45screen_protect.test \
src/libvterm/t/46screen_extent.test \
src/libvterm/t/47screen_dbl_wh.test \
src/libvterm/t/48screen_termprops.test \
src/libvterm/t/90vttest_01-movement-1.test \
src/libvterm/t/90vttest_01-movement-2.test \
src/libvterm/t/90vttest_01-movement-3.test \
src/libvterm/t/90vttest_01-movement-4.test \
src/libvterm/t/90vttest_02-screen-1.test \
src/libvterm/t/90vttest_02-screen-2.test \
src/libvterm/t/90vttest_02-screen-3.test \
src/libvterm/t/90vttest_02-screen-4.test \
src/libvterm/t/92lp1640917.test \
src/libvterm/t/harness.c \
src/libvterm/t/run-test.pl \
# source files for Unix only

View File

@@ -87,6 +87,7 @@ UninstPage instfiles
Function .onInit
MessageBox MB_YESNO|MB_ICONQUESTION \
"This will install Vim ${VER_MAJOR}.${VER_MINOR} on your computer.$\n Continue?" \
/SD IDYES \
IDYES NoAbort
Abort ; causes installer to quit.
NoAbort:

View File

@@ -101,6 +101,7 @@ DOCS = \
tabpage.txt \
tagsrch.txt \
term.txt \
terminal.txt \
tips.txt \
todo.txt \
uganda.txt \
@@ -236,6 +237,7 @@ HTMLS = \
tabpage.html \
tagsrch.html \
term.html \
terminal.html \
tips.html \
todo.html \
uganda.html \

View File

@@ -1,4 +1,4 @@
*autocmd.txt* For Vim version 8.0. Last change: 2017 Apr 07
*autocmd.txt* For Vim version 8.0. Last change: 2017 Jul 14
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -651,7 +651,8 @@ FileType When the 'filetype' option has been set. The
pattern is matched against the filetype.
<afile> can be used for the name of the file
where this option was set, and <amatch> for
the new value of 'filetype'.
the new value of 'filetype'. Navigating to
another window or buffer is not allowed.
See |filetypes|.
*FileWriteCmd*
FileWriteCmd Before writing to a file, when not writing the

View File

@@ -518,7 +518,7 @@ By default this reads the whole buffer. This can be changed with the "in_top"
and "in_bot" options.
A special mode is when "in_top" is set to zero and "in_bot" is not set: Every
time a line is added to the buffer, the last-but-one line will be send to the
time a line is added to the buffer, the last-but-one line will be sent to the
job stdin. This allows for editing the last line and sending it when pressing
Enter.
*channel-close-in*

View File

@@ -1,4 +1,4 @@
*cmdline.txt* For Vim version 8.0. Last change: 2016 Sep 27
*cmdline.txt* For Vim version 8.0. Last change: 2017 Jul 11
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -455,6 +455,9 @@ matches exactly one character.
The 'wildignorecase' option can be set to ignore case in filenames.
The 'wildmenu' option can be set to show the matches just above the command
line.
If you like tcsh's autolist completion, you can use this mapping:
:cnoremap X <C-L><C-D>
(Where X is the command key to use, <C-L> is CTRL-L and <C-D> is CTRL-D)

View File

@@ -1,4 +1,4 @@
*debug.txt* For Vim version 8.0. Last change: 2012 Feb 11
*debug.txt* For Vim version 8.0. Last change: 2017 Jul 15
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -53,7 +53,7 @@ Use this command to start Vim:
valgrind --log-file=valgrind.log --leak-check=full ./vim
Note: Vim will run much slower. If your .vimrc is big or you have several
plugins you need to be patient for startup, or run with the "-u NONE"
plugins you need to be patient for startup, or run with the "--clean"
argument.
There are often a few leaks from libraries, such as getpwuid() and

View File

@@ -1,4 +1,4 @@
*editing.txt* For Vim version 8.0. Last change: 2017 Apr 10
*editing.txt* For Vim version 8.0. Last change: 2017 Jun 20
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1328,9 +1328,11 @@ present in 'cpoptions' and "!" is not used in the command.
:chd[ir][!] [path] Same as |:cd|.
*:lc* *:lcd*
:lc[d][!] {path} Like |:cd|, but only set the current directory for the
current window. The current directory for other
windows is not changed. {not in Vi}
:lc[d][!] {path} Like |:cd|, but only set the current directory when
the cursor is in the current window. The current
directory for other windows is not changed, switching
to another window will stop using {path}.
{not in Vi}
*:lch* *:lchdir*
:lch[dir][!] Same as |:lcd|. {not in Vi}

View File

@@ -1,4 +1,4 @@
*eval.txt* For Vim version 8.0. Last change: 2017 Jun 13
*eval.txt* For Vim version 8.0. Last change: 2017 Jul 15
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -2369,6 +2369,12 @@ tagfiles() List tags files used
tan({expr}) Float tangent of {expr}
tanh({expr}) Float hyperbolic tangent of {expr}
tempname() String name for a temporary file
term_getsize() Dict get the size of a terminal
term_open() Job open a terminal window and run a job
term_scrape() List inspect terminal screen
term_sendkeys() Number send keystrokes to a terminal
term_setsize() Number set the size of a terminal
term_wait() Number wait for screen to be updated
test_alloc_fail({id}, {countdown}, {repeat})
none make memory allocation fail
test_autochdir() none enable 'autochdir' during startup
@@ -4189,14 +4195,14 @@ getchar([expr]) *getchar()*
not consumed. Return zero if no character available.
Without [expr] and when [expr] is 0 a whole character or
special key is returned. If it is an 8-bit character, the
special key is returned. If it is a single character, the
result is a number. Use nr2char() to convert it to a String.
Otherwise a String is returned with the encoded character.
For a special key it's a sequence of bytes starting with 0x80
(decimal: 128). This is the same value as the string
"\<Key>", e.g., "\<Left>". The returned value is also a
String when a modifier (shift, control, alt) was used that is
not included in the character.
For a special key it's a String with a sequence of bytes
starting with 0x80 (decimal: 128). This is the same value as
the String "\<Key>", e.g., "\<Left>". The returned value is
also a String when a modifier (shift, control, alt) was used
that is not included in the character.
When [expr] is 0 and Esc is typed, there will be a short delay
while Vim waits to see if this is the start of an escape
@@ -4586,6 +4592,7 @@ getqflist([{what}]) *getqflist()*
returns only the items listed in {what} as a dictionary. The
following string items are supported in {what}:
context get the context stored with |setqflist()|
items quickfix list entries
nr get information for this quickfix list; zero
means the current quickfix list and '$' means
the last quickfix list
@@ -4602,6 +4609,7 @@ getqflist([{what}]) *getqflist()*
The returned dictionary contains the following entries:
context context information stored with |setqflist()|
items quickfix list entries
nr quickfix list number
title quickfix list title text
winid quickfix |window-ID| (if opened)
@@ -6998,13 +7006,16 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
argument is ignored. The following items can be specified in
{what}:
context any Vim type can be stored as a context
items list of quickfix entries. Same as the {list}
argument.
nr list number in the quickfix stack; zero
means the current quickfix list and '$' means
the last quickfix list
title quickfix list title text
Unsupported keys in {what} are ignored.
If the "nr" item is not present, then the current quickfix list
is modified.
is modified. When creating a new quickfix list, "nr" can be
set to a value one greater than the quickfix stack size.
Examples: >
:call setqflist([], 'r', {'title': 'My search'})
@@ -7651,17 +7662,29 @@ synIDtrans({synID}) *synIDtrans()*
":highlight link" are followed.
synconcealed({lnum}, {col}) *synconcealed()*
The result is a List. The first item in the list is 0 if the
character at the position {lnum} and {col} is not part of a
concealable region, 1 if it is. The second item in the list is
a string. If the first item is 1, the second item contains the
text which will be displayed in place of the concealed text,
depending on the current setting of 'conceallevel'. The third
and final item in the list is a unique number representing the
specific syntax region matched. This allows detection of the
beginning of a new concealable region if there are two
consecutive regions with the same replacement character.
For an example use see $VIMRUNTIME/syntax/2html.vim .
The result is a List with currently three items:
1. The first item in the list is 0 if the character at the
position {lnum} and {col} is not part of a concealable
region, 1 if it is.
2. The second item in the list is a string. If the first item
is 1, the second item contains the text which will be
displayed in place of the concealed text, depending on the
current setting of 'conceallevel' and 'listchars'.
3. The third and final item in the list is a number
representing the specific syntax region matched in the
line. When the character is not concealed the value is
zero. This allows detection of the beginning of a new
concealable region if there are two consecutive regions
with the same replacement character. For an example, if
the text is "123456" and both "23" and "45" are concealed
and replace by the character "X", then:
call returns ~
synconcealed(lnum, 1) [0, '', 0]
synconcealed(lnum, 2) [1, 'X', 1]
synconcealed(lnum, 3) [1, 'X', 1]
synconcealed(lnum, 4) [1, 'X', 2]
synconcealed(lnum, 5) [1, 'X', 2]
synconcealed(lnum, 6) [0, '', 0]
synstack({lnum}, {col}) *synstack()*
@@ -7870,6 +7893,23 @@ tempname() *tempname()* *temp-file-name*
For MS-Windows forward slashes are used when the 'shellslash'
option is set or when 'shellcmdflag' starts with '-'.
term_getsize() *term_getsize()*
Get the size of a terminal. NOT IMPLEMENTED YET
term_open() *term_open()*
Open a terminal window and run a job. NOT IMPLEMENTED YET
term_scrape() *term_scrape()*
Inspect terminal screen. NOT IMPLEMENTED YET
term_sendkeys() *term_sendkeys()*
Send keystrokes to a terminal. NOT IMPLEMENTED YET
term_setsize() *term_setsize()*
Set the size of a terminal. NOT IMPLEMENTED YET
term_wait() *term_wait()*
Wait for screen to be updated. NOT IMPLEMENTED YET
test_alloc_fail({id}, {countdown}, {repeat}) *test_alloc_fail()*
This is for testing: If the memory allocation with {id} is
@@ -7926,8 +7966,19 @@ test_override({name}, {val}) *test_override()*
name effect when {val} is non-zero ~
redraw disable the redrawing() function
char_avail disable the char_avail() function
starting reset the "starting" variable, see below
ALL clear all overrides ({val} is not used)
"starting" is to be used when a test should behave like
startup was done. Since the tests are run by sourcing a
script the "starting" variable is non-zero. This is usually a
good thing (tests run faster), but sometimes changes behavior
in a way that the test doesn't work properly.
When using: >
call test_override('starting', 1)
< The value of "starting" is saved. It is restored by: >
call test_override('starting', 0)
test_settime({expr}) *test_settime()*
Set the time Vim uses internally. Currently only used for
timestamps in the history, as they are used in viminfo, and
@@ -7989,6 +8040,10 @@ timer_start({time}, {callback} [, {options}])
"repeat" Number of times to repeat calling the
callback. -1 means forever. When not present
the callback will be called once.
If the timer causes an error three times in a
row the repeat is cancelled. This avoids that
Vim becomes unusable because of all the error
messages.
Example: >
func MyHandler(timer)
@@ -8715,6 +8770,9 @@ See |:verbose-cmd| for more information.
not used an error message is given. When [!] is used,
an existing function is silently replaced. Unless it
is currently being executed, that is an error.
NOTE: Use ! wisely. If used without care it can cause
an existing function to be replaced unexpectedly,
which is hard to debug.
For the {arguments} see |function-argument|.
@@ -8764,18 +8822,36 @@ See |:verbose-cmd| for more information.
implies that the effect of |:nohlsearch| is undone
when the function returns.
*:endf* *:endfunction* *E126* *E193*
:endf[unction] The end of a function definition. Must be on a line
by its own, without other commands.
*:endf* *:endfunction* *E126* *E193* *W22*
:endf[unction] [argument]
The end of a function definition. Best is to put it
on a line by its own, without [argument].
[argument] can be:
| command command to execute next
\n command command to execute next
" comment always ignored
anything else ignored, warning given when
'verbose' is non-zero
The support for a following command was added in Vim
8.0.0654, before that any argument was silently
ignored.
To be able to define a function inside an `:execute`
command, use line breaks instead of |:bar|: >
:exe "func Foo()\necho 'foo'\nendfunc"
<
*:delf* *:delfunction* *E130* *E131* *E933*
:delf[unction] {name} Delete function {name}.
:delf[unction][!] {name}
Delete function {name}.
{name} can also be a |Dictionary| entry that is a
|Funcref|: >
:delfunc dict.init
< This will remove the "init" entry from "dict". The
function is deleted if there are no more references to
it.
With the ! there is no error if the function does not
exist.
*:retu* *:return* *E133*
:retu[rn] [expr] Return from a function. When "[expr]" is given, it is
evaluated and returned as the result of the function.

View File

@@ -1,4 +1,4 @@
*gui_x11.txt* For Vim version 8.0. Last change: 2016 Sep 12
*gui_x11.txt* For Vim version 8.0. Last change: 2017 Jun 27
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -279,8 +279,9 @@ For CDE "dtwm" (a derivative of Motif) add this line in the .Xdefaults: >
For "mwm" (Motif window manager) the line would be: >
Mwm*Vim*iconImage: /usr/local/share/vim/vim32x32.xpm
Mouse Pointers Available in X11 *X11_mouse_shapes*
Mouse Pointers Available in X11 ~
*X11_mouse_shapes*
By using the |'mouseshape'| option, the mouse pointer can be automatically
changed whenever Vim enters one of its various modes (e.g., Insert or
Command). Currently, the available pointers are:
@@ -354,6 +355,8 @@ to the GTK documentation, however little there is, on how to do this.
See http://developer.gnome.org/doc/API/2.0/gtk/gtk-Resource-Files.html
for more information.
Tooltip Colors ~
*gtk-tooltip-colors*
Example, which sets the tooltip colors to black on light-yellow: >
@@ -372,15 +375,122 @@ distribution.
For GTK+ 3, an effect similar to the above can be obtained by adding the
following snippet of CSS code to $XDG_HOME_DIR/gtk-3.0/gtk.css (usually,
$HOME/.config/gtk-3.0/gtk.css):
>
For GTK+ 3 < 3.20: >
.tooltip {
background-color: #ffffcc;
color: #000000;
}
<
For GTK+ 3 >= 3.20: >
Using Vim as a GTK+ plugin *gui-gtk-socketid*
tooltip {
background-color: #ffffcc;
text-shadow: none;
}
tooltip label {
color: #2e3436;
}
<
A Quick Look at GTK+ CSS ~
*gtk-css*
The contents of this subsection apply to GTK+ 3.20 or later which provides
stable support for GTK+ CSS:
https://developer.gnome.org/gtk3/stable/theming.html
GTK+ uses CSS for styling and layout of widgets. In this subsection, we'll
have a quick look at GTK+ CSS through simple, illustrative examples.
Example 1. Empty Space Adjustment ~
By default, the toolbar and the tabline of the GTK+ 3 GUI are somewhat larger
than those of the GTK+ 2 GUI. Some people may want to make them look similar
to the GTK+ 2 GUI in size.
To do that, we'll try reducing empty space around icons and labels that looks
apparently superfluous.
Add the following lines to $XDG_HOME_DIR/gtk-3.0/gtk.css (usually,
$HOME/.config/gtk-3.0/gtk.css): >
toolbar button {
margin-top: -2px;
margin-right: 0px;
margin-bottom: -2px;
margin-left: 0px;
padding-top: 0px;
padding-right: 0px;
padding-bottom: 0px;
padding-left: 0px
}
notebook tab {
margin-top: -1px;
margin-right: 3px;
margin-bottom: -1px;
margin-left: 3px;
padding-top: 0px;
padding-right: 0px;
padding-bottom: 0px;
padding-left: 0px
}
<
Since it's a CSS, they can be rewritten using shorthand: >
toolbar button {
margin: -2px 0px;
padding: 0px;
}
notebook tab {
margin: -1px 3px;
padding: 0px
}
<
Note: You might want to use 'toolbariconsize' to adjust the icon size, too.
Note: Depending on the icon theme and/or the font in use, some extra tweaks
may be needed for a satisfactory result.
Note: In addition to margin and padding, you can use border. For details,
refer to the box model of CSS, e.g.,
https://www.w3schools.com/css/css_boxmodel.asp
Example 2. More Than Just Colors ~
GTK+ CSS supports gradients as well: >
tooltip {
background-image: -gtk-gradient(linear,
0 0, 0 1,
color-stop(0, #344752),
color-stop(0.5, #546772),
color-stop(1, #243742));
}
tooltip label {
color: #f3f3f3;
}
<
Gradients can be used to make a GUI element visually distinguishable from
others without relying on high contrast. Accordingly, effective use of them is
a useful technique to give a theme a sense of unity in color and luminance.
Note: Theming can be difficult since it must make every application look
equally good; making a single application more charming often gets others
unexpectedly less attractive or even deteriorates their usability. Keep this
in mind always when you try improving a theme.
Using Vim as a GTK+ plugin ~
*gui-gtk-socketid*
When the GTK+ version of Vim starts up normally, it creates its own top level
window (technically, a 'GtkWindow'). GTK+ provides an embedding facility with
its GtkSocket and GtkPlug widgets. If one GTK+ application creates a
@@ -425,8 +535,8 @@ Note: Avoid use of --enable-gnome-check with GTK+ 3 GUI build. The
functionality mentioned above is consolidated in GTK+ 3.
GNOME session support *gui-gnome-session* *gnome-session*
GNOME session support ~
*gui-gnome-session* *gnome-session*
On logout, Vim shows the well-known exit confirmation dialog if any buffers
are modified. Clicking [Cancel] will stop the logout process. Otherwise the
current session is stored to disk by using the |:mksession| command, and

View File

@@ -1,4 +1,4 @@
*if_cscop.txt* For Vim version 8.0. Last change: 2011 Jun 12
*if_cscop.txt* For Vim version 8.0. Last change: 2017 Jun 14
VIM REFERENCE MANUAL by Andy Kahn
@@ -91,9 +91,10 @@ suggested use.)
2. Cscope related commands *cscope-commands*
*:cscope* *:cs* *:scs* *:scscope* *E259* *E262* *E561* *E560*
All cscope commands are accessed through suboptions to the main cscope
command ":cscope". The shortest abbreviation is ":cs". The ":scscope"
command does the same and also splits the window (short: "scs").
All cscope commands are accessed through suboptions to the cscope commands.
`:cscope` or `:cs` is the main command
`:scscope` or `:scs` does the same and splits the window
`:lcscope` or `:lcs` uses the location list, see |:lcscope|
The available subcommands are:

View File

@@ -1,4 +1,4 @@
*index.txt* For Vim version 8.0. Last change: 2017 Apr 22
*index.txt* For Vim version 8.0. Last change: 2017 Jul 15
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1573,6 +1573,7 @@ tag command action ~
|:tcldo| :tcld[o] execute Tcl command for each line
|:tclfile| :tclf[ile] execute Tcl script file
|:tearoff| :te[aroff] tear-off a menu
|:terminal| :ter[minal] open a terminal window
|:tfirst| :tf[irst] jump to first matching tag
|:throw| :th[row] throw an exception
|:tjump| :tj[ump] like ":tselect", but jump directly when there

View File

@@ -1,4 +1,4 @@
*options.txt* For Vim version 8.0. Last change: 2017 Jun 13
*options.txt* For Vim version 8.0. Last change: 2017 Jul 15
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -4966,8 +4966,8 @@ A jump table for the options with a short description can be found at |Q_op|.
When on the plugin scripts are loaded when starting up |load-plugins|.
This option can be reset in your |vimrc| file to disable the loading
of plugins.
Note that using the "-u NONE" and "--noplugin" command line arguments
reset this option. |-u| |--noplugin|
Note that using the "-u NONE", "-u DEFAULTS" and "--noplugin" command
line arguments reset this option. See |-u| and |--noplugin|.
*'luadll'*
'luadll' string (default depends on the build)
@@ -5945,10 +5945,14 @@ A jump table for the options with a short description can be found at |Q_op|.
{only available when compiled with the |+reltime|
feature}
The time in milliseconds for redrawing the display. This applies to
searching for patterns for 'hlsearch' and |:match| highlighting.
searching for patterns for 'hlsearch', |:match| highlighting an syntax
highlighting.
When redrawing takes more than this many milliseconds no further
matches will be highlighted. This is used to avoid that Vim hangs
when using a very complicated pattern.
matches will be highlighted.
For syntax highlighting the time applies per window. When over the
limit syntax highlighting is disabled until |CTRL-L| is used.
This is used to avoid that Vim hangs when using a very complicated
pattern.
*'regexpengine'* *'re'*
'regexpengine' 're' number (default 0)
@@ -7326,7 +7330,7 @@ A jump table for the options with a short description can be found at |Q_op|.
Watch out for errors in expressions. They may render Vim unusable!
If you are stuck, hold down ':' or 'Q' to get a prompt, then quit and
edit your .vimrc or whatever with "vim -u NONE" to get it right.
edit your .vimrc or whatever with "vim --clean" to get it right.
Examples:
Emulate standard status line with 'ruler' set >
@@ -7750,6 +7754,26 @@ A jump table for the options with a short description can be found at |Q_op|.
Note that the "cterm" attributes are still used, not the "gui" ones.
NOTE: This option is reset when 'compatible' is set.
*'termkey'* *'tk'*
'termkey' 'tk' string (default "CTRL-W")
local to window
{not in Vi}
The key that precedes a Vim command in a terminal window. Other keys
are sent to the job running in the window.
The string must be one key stroke.
NOT IMPLEMENTED YET
*'thesaurus'* *'tsr'*
'termsize' 'tms' string (default "")
local to window
{not in Vi}
Size of the |terminal| window. Format: {rows}x{columns}.
- When empty the terminal gets the size from the window.
- When set (e.g., "24x80") the terminal size is fixed. If the window
is smaller only the top-left part is displayed.
NOT IMPLEMENTED YET
*'terse'* *'noterse'*
'terse' boolean (default off)
global
@@ -8309,13 +8333,14 @@ A jump table for the options with a short description can be found at |Q_op|.
{not available when compiled without the |+viminfo|
feature}
When non-empty, the viminfo file is read upon startup and written
when exiting Vim (see |viminfo-file|). The string should be a comma
separated list of parameters, each consisting of a single character
identifying the particular parameter, followed by a number or string
which specifies the value of that parameter. If a particular
character is left out, then the default value is used for that
parameter. The following is a list of the identifying characters and
the effect of their value.
when exiting Vim (see |viminfo-file|). Except when 'viminfofile' is
"NONE".
The string should be a comma separated list of parameters, each
consisting of a single character identifying the particular parameter,
followed by a number or string which specifies the value of that
parameter. If a particular character is left out, then the default
value is used for that parameter. The following is a list of the
identifying characters and the effect of their value.
CHAR VALUE ~
*viminfo-!*
! When included, save and restore global variables that start
@@ -8375,9 +8400,9 @@ A jump table for the options with a short description can be found at |Q_op|.
has been used since the last search command.
*viminfo-n*
n Name of the viminfo file. The name must immediately follow
the 'n'. Must be at the end of the option! If the "-i"
argument was given when starting Vim, that file name overrides
the one given here with 'viminfo'. Environment variables are
the 'n'. Must be at the end of the option! If the
'viminfofile' option is set, that file name overrides the one
given here with 'viminfo'. Environment variables are
expanded when opening the file, not when setting the option.
*viminfo-r*
r Removable media. The argument is a string (up to the next
@@ -8418,6 +8443,17 @@ A jump table for the options with a short description can be found at |Q_op|.
NOTE: This option is set to the Vim default value when 'compatible'
is reset.
*'viminfofile'* *'vif'*
'viminfofile' 'vif' string (default: "")
global
{not in Vi}
{not available when compiled without the |+viminfo|
feature}
When non-empty, overrides the file name used for viminfo.
When equal to "NONE" no viminfo file will be read or written.
This option can be set with the |-i| command line flag. The |--clean|
command line flag sets it to "NONE".
*'virtualedit'* *'ve'*
'virtualedit' 've' string (default "")
global
@@ -8451,14 +8487,27 @@ A jump table for the options with a short description can be found at |Q_op|.
'visualbell' 'vb' boolean (default off)
global
{not in Vi}
Use visual bell instead of beeping. The terminal code to display the
Use a visual bell instead of beeping. The terminal code to display the
visual bell is given with 't_vb'. When no beep or flash is wanted,
use ":set vb t_vb=".
Note: When the GUI starts, 't_vb' is reset to its default value. You
might want to set it again in your |gvimrc|.
use: >
:set vb t_vb=
< If you want a short flash, you can use this on many terminals: >
:set vb t_vb=[?5h$<100>[?5l
< Here $<100> specifies the time, you can use a smaller or bigger value
to get a shorter or longer flash.
Note: Vim will limit the bell to once per half a second. This avoids
having to wait for the flashing to finish when there are lots of
bells, e.g. on key repeat. This also happens without 'visualbell'
set.
In the GUI, 't_vb' defaults to "<Esc>|f", which inverts the display
for 20 msec. If you want to use a different time, use "<Esc>|40f",
where 40 is the time in msec.
Note: When the GUI starts, 't_vb' is reset to its default value. You
might want to set it again in your |gvimrc|.
Does not work on the Amiga, you always get a screen flash.
Also see 'errorbells'.

View File

@@ -1,4 +1,4 @@
*quickref.txt* For Vim version 8.0. Last change: 2016 Dec 16
*quickref.txt* For Vim version 8.0. Last change: 2017 Jul 15
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -920,6 +920,8 @@ Short explanation of each option: *option-list*
'termbidi' 'tbidi' terminal takes care of bi-directionality
'termencoding' 'tenc' character encoding used by the terminal
'termguicolors' 'tgc' use GUI colors for the terminal
'termkey' 'tk' key that precedes a Vim command in a terminal
'termsize' 'tms' size of a terminal window
'terse' shorten some messages
'textauto' 'ta' obsolete, use 'fileformats'
'textmode' 'tx' obsolete, use 'fileformat'
@@ -1309,6 +1311,7 @@ Context-sensitive completion on the command-line:
|:sfind| :sf[ind] {file} split window, find {file} in 'path'
and edit it
|:terminal| :terminal {cmd} open a terminal window
|CTRL-W_]| CTRL-W ] split window and jump to tag under
cursor
|CTRL-W_f| CTRL-W f split window and edit file name under

View File

@@ -1,4 +1,4 @@
*starting.txt* For Vim version 8.0. Last change: 2017 Jan 15
*starting.txt* For Vim version 8.0. Last change: 2017 Jul 15
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -140,11 +140,12 @@ a slash. Thus "-R" means recovery and "-/R" readonly.
--noplugin Skip loading plugins. Resets the 'loadplugins' option.
{not in Vi}
Note that the |-u| argument may also disable loading plugins:
argument load vimrc files load plugins ~
(nothing) yes yes
-u NONE no no
-u NORC no yes
--noplugin yes no
argument load: vimrc files plugins defaults.vim ~
(nothing) yes yes yes
-u NONE no no no
-u DEFAULTS no no yes
-u NORC no yes no
--noplugin yes no yes
--startuptime {fname} *--startuptime*
During startup write timing messages to the file {fname}.
@@ -465,21 +466,30 @@ a slash. Thus "-R" means recovery and "-/R" readonly.
--nofork GUI: Do not fork. Same as |-f|.
*-u* *E282*
-u {vimrc} The file {vimrc} is read for initializations. Most other
initializations are skipped; see |initialization|. This can
be used to start Vim in a special mode, with special
initializations are skipped; see |initialization|.
This can be used to start Vim in a special mode, with special
mappings and settings. A shell alias can be used to make
this easy to use. For example: >
alias vimc vim -u ~/.c_vimrc !*
< Also consider using autocommands; see |autocommand|.
When {vimrc} is equal to "NONE" (all uppercase), all
initializations from files and environment variables are
skipped, including reading the |gvimrc| file when the GUI
starts. Loading plugins is also skipped.
When {vimrc} is equal to "NORC" (all uppercase), this has the
same effect as "NONE", but loading plugins is not skipped.
Using the "-u" argument has the side effect that the
'compatible' option will be on by default. This can have
unexpected effects. See |'compatible'|.
When {vimrc} is equal to "DEFAULTS" (all uppercase), this has
the same effect as "NONE", but the |defaults.vim| script is
loaded, which will also set 'nocompatible'.
Using the "-u" argument with another argument than DEFAULTS
has the side effect that the 'compatible' option will be on by
default. This can have unexpected effects. See
|'compatible'|.
{not in Vi}
*-U* *E230*
@@ -497,6 +507,13 @@ a slash. Thus "-R" means recovery and "-/R" readonly.
":rv" or ":wv" are used. See also |viminfo-file|.
{not in Vi}
*--clean*
--clean Equal to "-u DEFAULTS -i NONE":
- initializations from files and environment variables is
skipped
- the |defaults.vim| script is loaded, which implies
'nocompatible': use Vim defaults
- no viminfo file is read or written
*-x*
-x Use encryption to read/write files. Will prompt for a key,
which is then stored in the 'key' option. All writes will
@@ -868,6 +885,7 @@ accordingly. Vim proceeds in this order:
Loading plugins won't be done when:
- The 'loadplugins' option was reset in a vimrc file.
- The |--noplugin| command line argument is used.
- The |--clean| command line argument is used.
- The "-u NONE" command line argument is used |-u|.
- When Vim was compiled without the |+eval| feature.
Note that using "-c 'set noloadplugins'" doesn't work, because the
@@ -990,6 +1008,7 @@ starts its initializations. But as soon as:
- a vimrc file in the current directory, or
- the "VIMINIT" environment variable is set, or
- the "-N" command line argument is given, or
- the "--clean" command line argument is given, or
even when no vimrc file exists.
- the |defaults.vim| script is loaded, or
- gvimrc file was found,

View File

@@ -1,4 +1,4 @@
*syntax.txt* For Vim version 8.0. Last change: 2017 Jun 04
*syntax.txt* For Vim version 8.0. Last change: 2017 Jul 14
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -4982,10 +4982,11 @@ PmenuSbar Popup menu: scrollbar.
PmenuThumb Popup menu: Thumb of the scrollbar.
*hl-Question*
Question |hit-enter| prompt and yes/no questions
*hl-QuickFixLine*
QuickFixLine Current |quickfix| item in the quickfix window.
*hl-Search*
Search Last search pattern highlighting (see 'hlsearch').
Also used for highlighting the current line in the quickfix
window and similar items that need to stand out.
Also used for similar items that need to stand out.
*hl-SpecialKey*
SpecialKey Meta and special keys listed with ":map", also for text used
to show unprintable characters in the text, 'listchars'.

View File

@@ -3098,6 +3098,8 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
:tclfile if_tcl.txt /*:tclfile*
:te gui_w32.txt /*:te*
:tearoff gui_w32.txt /*:tearoff*
:ter terminal.txt /*:ter*
:terminal terminal.txt /*:terminal*
:tf tagsrch.txt /*:tf*
:tfirst tagsrch.txt /*:tfirst*
:th eval.txt /*:th*
@@ -4802,6 +4804,7 @@ W18 syntax.txt /*W18*
W19 autocmd.txt /*W19*
W20 if_pyth.txt /*W20*
W21 if_pyth.txt /*W21*
W22 eval.txt /*W22*
WORD motion.txt /*WORD*
WWW intro.txt /*WWW*
Win32 os_win32.txt /*Win32*
@@ -6571,6 +6574,7 @@ gs various.txt /*gs*
gsp.vim syntax.txt /*gsp.vim*
gstar pattern.txt /*gstar*
gt tabpage.txt /*gt*
gtk-css gui_x11.txt /*gtk-css*
gtk-tooltip-colors gui_x11.txt /*gtk-tooltip-colors*
gu change.txt /*gu*
gugu change.txt /*gugu*
@@ -6740,6 +6744,7 @@ hl-PmenuSbar syntax.txt /*hl-PmenuSbar*
hl-PmenuSel syntax.txt /*hl-PmenuSel*
hl-PmenuThumb syntax.txt /*hl-PmenuThumb*
hl-Question syntax.txt /*hl-Question*
hl-QuickFixLine syntax.txt /*hl-QuickFixLine*
hl-Scrollbar syntax.txt /*hl-Scrollbar*
hl-Search syntax.txt /*hl-Search*
hl-SignColumn syntax.txt /*hl-SignColumn*
@@ -8778,6 +8783,12 @@ tempname() eval.txt /*tempname()*
term-dependent-settings term.txt /*term-dependent-settings*
term-list syntax.txt /*term-list*
term.txt term.txt /*term.txt*
term_getsize() eval.txt /*term_getsize()*
term_open() eval.txt /*term_open()*
term_scrape() eval.txt /*term_scrape()*
term_sendkeys() eval.txt /*term_sendkeys()*
term_setsize() eval.txt /*term_setsize()*
term_wait() eval.txt /*term_wait()*
termcap term.txt /*termcap*
termcap-changed version4.txt /*termcap-changed*
termcap-colors term.txt /*termcap-colors*
@@ -8785,11 +8796,16 @@ termcap-cursor-color term.txt /*termcap-cursor-color*
termcap-cursor-shape term.txt /*termcap-cursor-shape*
termcap-options term.txt /*termcap-options*
termcap-title term.txt /*termcap-title*
terminal terminal.txt /*terminal*
terminal-colors os_unix.txt /*terminal-colors*
terminal-debug terminal.txt /*terminal-debug*
terminal-info term.txt /*terminal-info*
terminal-key-codes term.txt /*terminal-key-codes*
terminal-options term.txt /*terminal-options*
terminal-output-codes term.txt /*terminal-output-codes*
terminal-testing terminal.txt /*terminal-testing*
terminal-use terminal.txt /*terminal-use*
terminal.txt terminal.txt /*terminal.txt*
terminfo term.txt /*terminfo*
termresponse-variable eval.txt /*termresponse-variable*
test-functions usr_41.txt /*test-functions*

126
runtime/doc/terminal.txt Normal file
View File

@@ -0,0 +1,126 @@
*terminal.txt* For Vim version 8.0. Last change: 2017 Jul 15
VIM REFERENCE MANUAL by Bram Moolenaar
Terminal window support *terminal*
WARNING: THIS IS ONLY PARTLY IMPLEMENTED, ANYTHING CAN STILL CHANGE
1. Basic use |terminal-use|
2. Remote testing |terminal-testing|
3. Debugging |terminal-debug|
{Vi does not have any of these commands}
==============================================================================
1. Basic use *terminal-use*
This feature is for running a terminal emulator in a Vim window. A job can be
started connected to the terminal emulator. For example, to run a shell: >
:term bash
Or to run a debugger: >
:term gdb vim
The job runs asynchronously from Vim, the window will be updated to show
output from the job, also while editing in any other window.
When the keyboard focus is in the terminal window, typed keys will be send to
the job. This uses a pty when possible.
Navigate between windows with CTRL-W commands (and mouse).
E.g. CTRL-W CTRL-W moves focus to the next window.
See option 'termkey' for specifying the key that precedes a Vim command.
Default is CTRL-W.
See option 'termsize' for controlling the size of the terminal window.
(TODO: scrolling when the terminal is larger than the window)
Syntax ~
*:ter* *:terminal*
:terminal[!] [command] Open a new terminal window.
If [command] is provided run it as a job and connect
the input and output to the terminal.
If [command] is not given the 'shell' option is used.
A new buffer will be created, using [command] or
'shell' as the name. If a buffer by this name already
exists a number is added in parenthesis.
E.g. if "gdb" exists the second terminal buffer will
use "gdb (1)".
The window can be closed, in which case the buffer
becomes hidden. The command will not be stopped. The
`:buffer` command can be used to turn the current
window into a terminal window, using the existing
buffer. If there are unsaved changes this fails, use
! to force, as usual.
Resizing ~
The size of the terminal can be in one of three modes:
1. The 'termsize' option is empty: The terminal size follows the window size.
The minimal size is 2 screen lines with 10 cells.
2. The 'termsize' option is "rows*cols", where "rows" is the minimal number of
screen rows and "cols" is the minial number of cells.
3. The 'termsize' option is "rowsXcols" (where the x is upper or lower case).
The terminal size is fixed to the specified number of screen lines and
cells. If the window is bigger there will be unused empty space.
If the window is smaller than the terminal size, only part of the terminal can
be seen (the lower-left part).
The |term_getsize()| function can be used to get the current size of the
terminal. |term_setsize()| can be used only when in the first or second mode,
not when 'termsize' is "rowsXcols".
==============================================================================
2. Remote testing *terminal-testing*
Most Vim tests execute a script inside Vim. For some tests this does not
work, running the test interferes with the code being tested. To avoid this
Vim is executed in a terminal window. The test sends keystrokes to it and
inspects the resulting screen state.
Functions ~
term_sendkeys() send keystrokes to a terminal
term_wait() wait for screen to be updated
term_scrape() inspect terminal screen
==============================================================================
3. Debugging *terminal-debug*
The Terminal debugging plugin can be used to debug a program with gdb and view
the source code in a Vim window. For example: >
:TermDebug vim
This opens three windows:
- A terminal window in which "gdb vim" is executed. Here you can directly
interact with gdb.
- A terminal window for the executed program. When "run" is used in gdb the
program I/O will happen in this window, so that it does not interfere with
controlling gdb.
- A normal Vim window used to show the source code. When gdb jumps to a
source file location this window will display the code, if possible. Values
of variables can be inspected, breakpoints set and cleared, etc.
This uses two terminal windows. To open the gdb window: >
:term gdb [arguments]
To open the terminal to run the tested program |term_open()| is used.
TODO
vim:tw=78:ts=8:ft=help:norl:

View File

@@ -1,4 +1,4 @@
*todo.txt* For Vim version 8.0. Last change: 2017 Jun 13
*todo.txt* For Vim version 8.0. Last change: 2017 Jul 15
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -35,9 +35,39 @@ entered there will not be repeated below, unless there is extra information.
*known-bugs*
-------------------- Known bugs and current work -----------------------
+channel:
- When redrawing for the channel buffer, command line completion is cleared.
When redrawing for the channel buffer, command line completion is cleared.
(Ramel Eshed, 2017 May 4)
When a timer triggers the command completion disappears. (Dominique Pelle,
2017 Jun 13, #1768)
Caused by 8.0.0592.
Check if anything was output? Don't redraw when scrolled. (#1820)
When redrawing the command line a pending CTRL-R shows ", which is removed.
No maintainer for German translations.
No maintainer for Vietnamese translations.
No maintainer for Simplified Chinese translations.
Terminal emulator window:
- Lots of stuff to implement, see src/terminal.c
- Windows implementation (WiP): https://github.com/mattn/vim/tree/terminal
Using winpty ?
- Running a shell command from the GUI still has limitations. Look into how
the terminal emulator of the Vim shell project can help:
http://vimshell.wana.at
- Add debugger interface. Implementation for gdb by Xavier de Gaye.
Should work like an IDE. Try to keep it generic. Now found here:
http://clewn.sf.net.
- Look into the idevim plugin/script.
- Related wishes for NetBeans commands:
- make it possible to have 'defineAnnoType' also handle terminal colors.
- send 'balloonText' events for the cursor position (using CursorHold ?)
in terminal mode.
- Feature: switch between "running job" and a normal buffer (possibly
read-only) to allow for searching, copy/paste, etc. (Domnique). Having a
(large) scrollback would be useful.
+channel:
- Try out background make plugin:
https://github.com/AndrewVos/vim-make-background
- Problem with stderr on Windows? (Vincent Rischmann, 2016 Aug 31, #1026)
@@ -101,14 +131,14 @@ Regexp problems:
col and vcol when moving to another line.
- this doesn't work: "syntax match ErrorMsg /.\%9l\%>20c\&\%<28c/". Leaving
out the \& works. Seems any column check after \& fails.
- The pattern "\1" with the old engine gives E65, with the new engine it
matches the empty string. (Dominique Pelle, 2015 Oct 2, Nov 24)
had_endbrace[] is set but not initialized or used.
- Difference between two engines: ".*\zs\/\@>\/" on text "///"
(Chris Paul, 2016 Nov 13) New engine not greedy enough?
Another one: echom matchstr(" sdfsfsf\n sfdsdfsdf",'[^\n]*')
(2017 May 15, #1252)
Patch to update b:changedtick in the quickfix window. (Yegappan Lakshmanan,
2017 Jul 13)
With foldmethod=syntax and nofoldenable comment highlighting isn't removed.
(Marcin Szewczyk, 2017 Apr 26)
@@ -119,13 +149,38 @@ ml_get errors with buggy script. (Dominique, 2017 Apr 30)
Error in emsg with buggy script. (Dominique, 2017 Apr 30)
Better detection of strace file. (Steven Fernandez, 2017 Jul 12, #1837)
To reproduce problems "vim -u NONE -N" is often used, but this still uses
'viminfo'. Add "-I" to not use 'viminfo'?
Or use "vim -B" for "bug reproduction"?
Bug with conceal mode: 3rd element returned by synconcealed() differs for
every call. (Dominique Pelle, 2017 Jun 18)
Add options_default() / options_restore() to set several options to Vim
defaults for a plugin. Comments from Zyx, 2017 May 10.
Perhaps use a vimcontext / endvimcontext command block.
Using freed memory with "qf" FileType autocommand that does :cclose.
(Lemonboy, 2017 May 28, #1730, fix in 1734, with test that doesn't fail, but
it fails when run manually) Add "starting" to test_override()?
Patch to trigger OptionSet when entering diff mode. (Christian Brabandt, 2017
Jul 7)
Illegal memory access, requires ASAN to see. (Dominique Pelle, 2015 Jul 28)
Still happens (2017 Jul 9)
Memory leak in test_arabic.
Refactored HTML indent file. (Michael Lee, #1821)
Using uninitialzed value in test_crypt.
X11: Putting more than about 262040 characters of text on the clipboard and
pasting it in another Vim doesn't work. (Dominique Pelle, 2008 Aug 21-23)
clip_x11_request_selection_cb() is called with zero value and length.
Also: Get an error message from free() in the process that owns the selection.
Seems to happen when the selection is requested the second time, but before
clip_x11_convert_selection_cb() is invoked, thus in X library code.
Patch to fix this by Kiichi, 2017 Jul 11, #1822)
Problem with three-piece comment. (Michael Lee, 2017 May 11, #1696)
@@ -134,15 +189,24 @@ case of :bwipe followed by :new.
Files for Latvian language. (Vitolins, 2017 May 3, #1675)
MS-Windows: Opening same file in a second gvim hangs. (Sven Bruggemann, 2017
Jul 4)
Setting 'clipboard' to "unnamed" makes a global command very slow (Daniel
Drucker, 2017 May 8).
This was supposed to be fixed, did it break again somehow?
Christian cannot reproduce it.
Using composing char in mapping does not work properly. maparg() shows the
wrong thing. (Nikolai Pavlov, 2017 Jul 8, #1827)
Or is this not an actual problem?
Better TeX indent file. (Christian Brabandt, 2017 May 3)
Openhab syntax file (mueller, #1678)
Patch to use a separate code for BS on Windows. (Linwei, #1823)
Use gvimext.dll from the nightly build? (Issue #249)
'synmaxcol' works with bytes instead of screen cells. (Llandon, 2017 May 31,
@@ -151,18 +215,17 @@ Use gvimext.dll from the nightly build? (Issue #249)
Problem with using :cd when remotely editing a file. (Gerd Wachsmuth, 2017 May
8, #1690)
'equalalways' only works for one column. (Glacambre, 2017 May 15, #1707)
Include solarized color scheme?
Updates to GTK help. (Kazunobu Kuriyama, 2017 May 4)
Running test_gui and test_gui_init with Motif sometimes kills the window
manager. Problem with Motif?
Bogus characters inserted when triggering indent while changing text.
(Vitor Antunes, 2016 Nov 22, #1269)
Using "wviminfo /tmp/viminfo" does not store file marks that Vim knows about,
it only works when merging with an existing file. (Shougo, 2017 Jun 19, #1781)
Segmentation fault with complete(). (Lifepillar, 2017 Apr 29, #1668)
Check for "pat" to be NULL in search_for_exact_line()?
How did it get NULL? Comment by Christian, Apr 30.
@@ -172,6 +235,9 @@ Is it possible to keep the complete menu open when calling complete()?
Memory leak in test97? The string is actually freed. Weird.
assert_fails() can only check for the first error. Make it possible to have
it catch multiple errors and check all of them.
New value "uselast" for 'switchbuf'. (Lemonboy, 2017 Apr 23, #1652)
Add a toolbar in the terminal. Can be global, above all windows, or specific
@@ -187,6 +253,11 @@ Perhaps simpler: actually delete the mappings. Use maplist() to list matching
mappings (with a lhs prefix, like maparg()), mapdelete() to delete,
maprestore() to restore (using the output of maplist().
Patch to add setbufline(). (email from Yasuhiro Matsumoto, patch by Ozaki
Kiichi, 2016 Feb 28)
Update Mar 8: https://gist.github.com/mattn/23c1f50999084992ca98
Update Mar 13: https://gist.github.com/mattn/23c1f50999084992ca98
Add an argument to :mkvimrc (or add aother command) to skip mappings from
plugins (source is a Vim script). No need to put these in a .vimrc, they will
be defined when the plugin is loaded.
@@ -200,6 +271,9 @@ What if there is an invalid character?
Json string with trailing \u should be an error. (Lcd)
import can't be used in define option when include matches too.
(Romain Lafourcade, 2017 Jun 18, #1519)
When session file has name in argument list but the buffer was deleted, the
buffer is not deleted when using the session file. (#1393)
Should add the buffer in hidden state.
@@ -211,10 +285,6 @@ Wrong diff highlighting with three files. (2016 Oct 20, #1186)
Also get E749 on exit.
Another example in #1309
Patch to change all use of &sw to shiftwidth(). (Tyru, 2017 Feb 19)
Takuya Fujiwara
Wait until maintainers integrate it.
When deleting a mark or register, leave a tombstone, so that it's also deleted
when writing viminfo (and the delete was the most recent action). #1339
@@ -244,6 +314,12 @@ highlighting for both stl and stlnc. Patch by Ken Hamada (itchyny, 2016 Dec 11)
Using CTRL-G_U in InsertCharPre causes trouble for redo. (Israel Chauca
Fuentes, 2017 Feb 12, #1470)
Add a "keytrans()" function, which turns the internal byte representation of a
key into a form that can be used for :map. E.g.
let xx = "\<C-Home>"
echo keytrans(xx)
<C-Home>
Check for errors E704 and E705 only does VAR_FUNC, should also do VAR_PARTIAL.
(Nikolai Pavlov, 2017 Mar 13, #1557)
Make a function to check for function-like type?
@@ -257,9 +333,6 @@ Implement optional arguments for functions.
call Foo(12, all = 0)
call Foo(12, 15, 0)
writefile() does not abort as soon as an error is found. (Nikolai Pavlov,
2017 Feb 14, #1476)
Patch to support on-the-spot and over-the-spot input method. (Ken Takata, 2017
Feb 14).
@@ -273,6 +346,10 @@ somewhere else. :{range}copy {dest} !cmd
Patch to fix that empty first tab is not in session.
(Hirohito Higashi, 2016 Nov 25, #1282)
Patch to add random number generator. (Hong Xu, 2010 Nov 8, update Nov 10)
Alternative from Christian Brabandt. (2010 Sep 19)
New one from Yasuhiro Matsumoto, #1277.
Patch for restoring wide characters in the console buffer.
(Ken Takata, 2016 Jun 7)
@@ -286,9 +363,6 @@ The TermResponse event is not triggered when a plugin has set 'eventignore' to
"all". Netrw does this. (Gary Johnson, 2017 Jan 24)
Postpone the event until 'eventignore' is reset.
Patch to make urxvt mouse work better, recognize Esc[*M termcap code.
(Maurice Bos, 2017 Feb 17, #1486)
Expanding /**/ is slow. Idea by Luc Hermitte, 2017 Apr 14.
Once .exe with updated installer is available: Add remark to download page
@@ -324,11 +398,24 @@ Does this also fix #1408 ?
Patch to add "module" to quickfix entries. (Coot, 2017 Jun 8, #1757)
'cursorline' and match interfere. (Ozaki Kiichi, 2017 Jun 23, #1792)
Patch for 'cursorlinenr' option. (Ozaki Kiichi, 2016 Nov 30)
Patch to be able to separately map CTRL-H and BS on Windows.
(Linwei, 2017 Jul 11, #1833)
When 'completeopt' has "noselect" does not insert a newline. (Lifepillar, 2017
Apr 23, #1653)
Using an external diff is inefficient. Not all systems have a good diff
program available (esp. MS-Windows). Would be nice to have in internal diff
implementation. Can then also use this for displaying changes within a line.
Olaf Dabrunz is working on this. (10 Jan 2016)
9 Instead invoking an external diff program, use builtin code. One can be
found here: http://www.ioplex.com/~miallen/libmba/dl/src/diff.c
It's complicated and badly documented.
Window resizing with 'winfixheight': With a vertical split the height changes
anyway. (Tommy allen, 2017 Feb 21, #1502)
@@ -385,9 +472,6 @@ Include the test.
Patch to add tagfunc(). Cleaned up by Christian Brabandt, 2013 Jun 22.
New update 2017 Apr 10, #1628
Unnamed register only contains the last deleted text when appending deleted
text to a register. (Wolfgang Jeltsch, reproduced by Ben Fritz, 2017 Apr 10)
When 'keywordprg' starts with ":" the argument is still escaped as a shell
command argument. (Romain Lafourcade, 2016 Oct 16, #1175)
@@ -405,6 +489,8 @@ execute() cannot be used with command completeion. (Daniel Hahler, 2016 Oct 1,
cmap using execute() has side effects. (Killthemule, 2016 Aug 17, #983)
:map X may print invalid data. (Nikolay Pavlov, 2017 Jul 3, #1816)
Patch to order results from taglist(). (Duncan McDougall, 2016 Oct 25)
patch for 'spellcamelcase' option: spellcheck each CamelCased word.
@@ -502,9 +588,6 @@ Because of using the initial buffer? (Dun Peal, 2016 May 12)
Patch to add the :bvimgrep command. (Christian Brabandt, 2014 Nov 12)
Updated 2016 Jun 10, #858 Update 2017 Mar 28: use <buffer>
Patch to fix that an encoding conversion failure results in a corrupted or
empty file. (Christian Brabandt, #1765, https://github.com/chrisbra/vim-mq-patches/blob/master/conversion_error)
Add redrawtabline command. (Naruhiko Nishino, 2016 Jun 11)
Neovim patch for utfc_ptr2char_len() https://github.com/neovim/neovim/pull/4574
@@ -522,11 +605,6 @@ Possibly include the needed code so that it can be build everywhere.
Add a way to restart a timer. It's similar to timer_stop() and timer_start(),
but the reference remains valid.
Patch to add setbufline(). (email from Yasuhiro Matsumoto, patch by Ozaki
Kiichi, 2016 Feb 28)
Update Mar 8: https://gist.github.com/mattn/23c1f50999084992ca98
Update Mar 13: https://gist.github.com/mattn/23c1f50999084992ca98
Need to try out instructions in INSSTALLpc.txt about how to install all
interfaces and how to build Vim with them.
Appveyor build with self-installing executable, includes getting most
@@ -639,8 +717,6 @@ Patch to add TagNotFound autocommand. (Anton Lindqvist, 2016 Feb 3)
Patch to add Error autocommand. (Anton Lindqvist, 2016 Feb 17)
Only remembers one error.
Illegal memory access, requires ASAN to see. (Dominique Pelle, 2015 Jul 28)
Gvim: when both Tab and CTRL-I are mapped, use CTRL-I not for Tab.
Unexpected delay when using CTRL-O u. It's not timeoutlen.
@@ -708,11 +784,6 @@ Patch to use two highlight groups for relative numbers. (Shaun Brady, 2016 Jan
MS-Windows: Crash opening very long file name starting with "\\".
(Christian Brock, 2012 Jun 29)
Using an external diff is inefficient. Not all systems have a good diff
program available (esp. MS-Windows). Would be nice to have in internal diff
implementation. Can then also use this for displaying changes within a line.
Olaf Dabrunz is working on this.
The OptionSet autocommand event is not always triggered. (Rick Howe, 2015 Sep
24): :diffthis, :diffoff.
@@ -1408,9 +1479,6 @@ New esperanto spell file can't be processed. (Dominique Pelle, 2011 Jan 30)
Editing a file with a ^M with 'ff' set to "mac", opening a help file, then the
^M is displayed as ^J sometimes. Getting 'ff' value from wrong window/buffer?
'colorcolumn' has higher priority than hlsearch. Should probably be the other
way around. (Nazri Ramliy, 2013 Feb 19)
When Vim is put in the background (SIGTSTP) and then gets a SIGHUP it doesn't
exit. It exists as soon as back in the foreground. (Stephen Liang, 2011 Jan
9) Caused by vim_handle_signal(SIGNAL_BLOCK); in ui.c.
@@ -1459,14 +1527,13 @@ setpos() does not restore cursor position after :normal. (Tyru, 2010 Aug 11)
7 The 'directory' option supports changing path separators to "%" to make
file names unique, also support this for 'backupdir'. (Mikolaj Machowski)
Patch by Christian Brabandt, 2010 Oct 21.
Is this an update: related to: #179
https://github.com/chrisbra/vim-mq-patches/blob/master/backupdir
Fixed patch 2017 Jul 1.
With "tw=55 fo+=a" typing space before ) doesn't work well. (Scott Mcdermott,
2010 Oct 24)
Patch to add random number generator. (Hong Xu, 2010 Nov 8, update Nov 10)
Alternative from Christian Brabandt. (2010 Sep 19)
New one from Yasuhiro Matsumoto, #1277.
Messages in message.txt are highlighted as examples.
When using cp850 the NBSP (0xff) is not drawn correctly. (Brett Stahlman, 2010
@@ -2406,13 +2473,6 @@ respond to selection requests. Invoking XtDisownSelection() before executing
the shell doesn't help. Would require forking and doing a message loop, like
what happens for the GUI.
X11: Putting more than about 262040 characters of text on the clipboard and
pasting it in another Vim doesn't work. (Dominique Pelle, 2008 Aug 21-23)
clip_x11_request_selection_cb() is called with zero value and length.
Also: Get an error message from free() in the process that owns the selection.
Seems to happen when the selection is requested the second time, but before
clip_x11_convert_selection_cb() is invoked, thus in X library code.
":vimgrep" does not recognize a recursive symlink. Is it possible to detect
this, at least for Unix (using device/inode)?
@@ -3275,18 +3335,6 @@ Most interesting new features to be added when all bugs have been fixed:
Alternative: Make a function for Ex commands: cmd_edit().
- Add COLUMN NUMBERS to ":" commands ":line1,line2[col1,col2]cmd". Block
can be selected with CTRL-V. Allow '$' (end of line) for col2.
- Add DEBUGGER INTERFACE. Implementation for gdb by Xavier de Gaye.
Should work like an IDE. Try to keep it generic. Now found here:
http://clewn.sf.net.
And the idevim plugin/script.
To be able to start the debugger from inside Vim: For GUI run a program
with a netbeans connection; for console: start a program that splits the
terminal, runs the debugger in one window and reconnect Vim I/O to the
other window.
Wishes for NetBeans commands:
- make it possible to have 'defineAnnoType' also handle terminal colors.
- send 'balloonText' events for the cursor position (using CursorHold ?)
in terminal mode.
- ECLIPSE plugin. Problem is: the interface is very complicated. Need to
implement part in Java and then connect to Vim. Some hints from Alexandru
Roman, 2004 Dec 15. Should then also work with Oracle Jdeveloper, see JSR
@@ -3299,9 +3347,6 @@ Most interesting new features to be added when all bugs have been fixed:
scrolls back to where the cursor is.
- Scroll commands by screen line. g CTRL-E and g CTRL-Y ? Requires the
first line to be able to start halfway.
- Running a shell command from the GUI still has limitations. Look into how
the terminal emulator of the Vim shell project can help:
http://vimshell.wana.at
8 Add a command to jump to a certain kind of tag. Allow the user to specify
values for the optional fields. E.g., ":tag size type=m".
Also allow specifying the file and command, so that the result of
@@ -3490,9 +3535,6 @@ Spell checking:
Diff mode:
9 When making small changes, e.g. deleting a character, update the diff.
Possibly without running diff.
9 Instead invoking an external diff program, use builtin code. One can be
found here: http://www.ioplex.com/~miallen/libmba/dl/src/diff.c
It's quite big and badly documented though.
8 Also show difference with the file when editing started? Should show what
can be undone. (Tom Popovich)

View File

@@ -1,4 +1,4 @@
*usr_01.txt* For Vim version 8.0. Last change: 2010 Nov 03
*usr_01.txt* For Vim version 8.0. Last change: 2017 Jul 15
VIM USER MANUAL - by Bram Moolenaar
@@ -140,19 +140,19 @@ On other systems, you have to do a little work:
1. Copy the tutor file. You can do this with Vim (it knows where to find it):
>
vim -u NONE -c 'e $VIMRUNTIME/tutor/tutor' -c 'w! TUTORCOPY' -c 'q'
vim --clean -c 'e $VIMRUNTIME/tutor/tutor' -c 'w! TUTORCOPY' -c 'q'
<
This will write the file "TUTORCOPY" in the current directory. To use a
translated version of the tutor, append the two-letter language code to the
filename. For French:
>
vim -u NONE -c 'e $VIMRUNTIME/tutor/tutor.fr' -c 'w! TUTORCOPY' -c 'q'
vim --clean -c 'e $VIMRUNTIME/tutor/tutor.fr' -c 'w! TUTORCOPY' -c 'q'
<
2. Edit the copied file with Vim:
>
vim -u NONE -c "set nocp" TUTORCOPY
vim --clean TUTORCOPY
<
The extra arguments make sure Vim is started in a good mood.
The --clean argument makes sure Vim is started with nice defaults.
3. Delete the copied file when you are finished with it:
>

View File

@@ -16827,7 +16827,7 @@ Patch 8.0.0388
Problem: filtering lines through "cat", without changing the line count,
changes manual folds.
Solution: Change how marks and folds are adjusted. (Matthew Malcomson, from
neovim #6194.
neovim #6194).
Files: src/fold.c, src/testdir/test_fold.vim
Patch 8.0.0389
@@ -17499,7 +17499,7 @@ Files: src/evalfunc.c, src/if_xcmdsrv.c, src/proto/if_xcmdsrv.pro,
Patch 8.0.0493
Problem: Crash with cd command with very long argument.
Solution: Check for running out of space. (Dominique pending, closes #1576)
Solution: Check for running out of space. (Dominique Pelle, closes #1576)
Files: src/testdir/test_alot.vim, src/testdir/test_cd.vim, src/Makefile,
src/misc2.c

View File

@@ -1,7 +1,7 @@
" Vim support file to detect file types
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
" Last Change: 2017 Jun 12
" Last Change: 2017 Jul 11
" Listen very carefully, I will say this only once
if exists("did_load_filetypes")
@@ -48,6 +48,9 @@ func! s:StarSetf(ft)
endif
endfunc
" Vim help file
au BufNewFile,BufRead $VIMRUNTIME/doc/*.txt setf help
" Abaqus or Trasys
au BufNewFile,BufRead *.inp call s:Check_inp()
@@ -632,7 +635,13 @@ au BufNewFile,BufRead dict.conf,.dictrc setf dictconf
au BufNewFile,BufRead dictd.conf setf dictdconf
" Diff files
au BufNewFile,BufRead *.diff,*.rej,*.patch setf diff
au BufNewFile,BufRead *.diff,*.rej setf diff
au BufNewFile,BufRead *.patch
\ if getline(1) =~ '^From [0-9a-f]\{40\} Mon Sep 17 00:00:00 2001$' |
\ setf gitsendemail |
\ else |
\ setf diff |
\ endif
" Dircolors
au BufNewFile,BufRead .dir_colors,.dircolors,*/etc/DIR_COLORS setf dircolors
@@ -801,6 +810,7 @@ if !empty($XDG_CONFIG_HOME)
au BufNewFile,BufRead $XDG_CONFIG_HOME/git/config setf gitconfig
endif
au BufNewFile,BufRead git-rebase-todo setf gitrebase
au BufRead,BufNewFile .gitsendemail.msg.?????? setf gitsendemail
au BufNewFile,BufRead .msg.[0-9]*
\ if getline(1) =~ '^From.*# This line is ignored.$' |
\ setf gitsendemail |
@@ -2786,7 +2796,13 @@ au BufNewFile,BufRead zsh*,zlog* call s:StarSetf('zsh')
" Plain text files, needs to be far down to not override others. This avoids
" the "conf" type being used if there is a line starting with '#'.
au BufNewFile,BufRead *.txt,*.text,README setf text
au BufNewFile,BufRead *.text,README setf text
" Help files match *.txt but should have a last line that is a modeline.
au BufNewFile,BufRead *.txt
\ if getline('$') !~ 'vim:.*ft=help'
\| setf text
\| endif
" Use the filetype detect plugins. They may overrule any of the previously

View File

@@ -1,7 +1,7 @@
" These commands create the option window.
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
" Last Change: 2017 Mar 06
" Last Change: 2017 Jul 15
" If there already is an option window, jump to that one.
if bufwinnr("option-window") > 0
@@ -506,6 +506,14 @@ if has("cursorbind")
call append("$", "\t(local to window)")
call <SID>BinOptionL("crb")
endif
if has("terminal")
call append("$", "termsize\tsize of a terminal window")
call append("$", "\t(local to window)")
call <SID>OptionL("tms")
call append("$", "termkey\tkey that precedes Vim commands in a terminal window")
call append("$", "\t(local to window)")
call <SID>OptionL("tk")
endif
call <SID>Header("multiple tab pages")

127
runtime/syntax/murphi.vim Normal file
View File

@@ -0,0 +1,127 @@
" Vim syntax file
" Language: Murphi model checking language
" Maintainer: Matthew Fernandez <matthew.fernandez@gmail.com>
" Last Change: 2017 May 3
" Version: 2
" Remark: Originally authored by Diego Ongaro <ongaro@cs.stanford.edu>
if version < 600
syntax clear
elseif exists("b:current_syntax")
finish
endif
" Keywords are case insensitive.
" Keep these in alphabetical order.
syntax case ignore
syn keyword murphiKeyword alias
syn keyword murphiStructure array
syn keyword murphiKeyword assert
syn keyword murphiKeyword begin
syn keyword murphiType boolean
syn keyword murphiKeyword by
syn keyword murphiLabel case
syn keyword murphiKeyword clear
syn keyword murphiLabel const
syn keyword murphiRepeat do
syn keyword murphiConditional else
syn keyword murphiConditional elsif
syn keyword murphiKeyword end
syn keyword murphiKeyword endalias
syn keyword murphiRepeat endexists
syn keyword murphiRepeat endfor
syn keyword murphiRepeat endforall
syn keyword murphiKeyword endfunction
syn keyword murphiConditional endif
syn keyword murphiKeyword endprocedure
syn keyword murphiStructure endrecord
syn keyword murphiKeyword endrule
syn keyword murphiKeyword endruleset
syn keyword murphiKeyword endstartstate
syn keyword murphiConditional endswitch
syn keyword murphiRepeat endwhile
syn keyword murphiStructure enum
syn keyword murphiKeyword error
syn keyword murphiRepeat exists
syn keyword murphiBoolean false
syn keyword murphiRepeat for
syn keyword murphiRepeat forall
syn keyword murphiKeyword function
syn keyword murphiConditional if
syn keyword murphiKeyword in
syn keyword murphiKeyword interleaved
syn keyword murphiLabel invariant
syn keyword murphiFunction ismember
syn keyword murphiFunction isundefined
syn keyword murphiKeyword log
syn keyword murphiStructure of
syn keyword murphiType multiset
syn keyword murphiFunction multisetadd
syn keyword murphiFunction multisetcount
syn keyword murphiFunction multisetremove
syn keyword murphiFunction multisetremovepred
syn keyword murphiKeyword procedure
syn keyword murphiKeyword process
syn keyword murphiKeyword program
syn keyword murphiKeyword put
syn keyword murphiStructure record
syn keyword murphiKeyword return
syn keyword murphiLabel rule
syn keyword murphiLabel ruleset
syn keyword murphiType scalarset
syn keyword murphiLabel startstate
syn keyword murphiConditional switch
syn keyword murphiConditional then
syn keyword murphiRepeat to
syn keyword murphiKeyword traceuntil
syn keyword murphiBoolean true
syn keyword murphiLabel type
syn keyword murphiKeyword undefine
syn keyword murphiStructure union
syn keyword murphiLabel var
syn keyword murphiRepeat while
syn keyword murphiTodo contained todo xxx fixme
syntax case match
" Integers.
syn match murphiNumber "\<\d\+\>"
" Operators and special characters.
syn match murphiOperator "[\+\-\*\/%&|=!<>:\?]\|\."
syn match murphiDelimiter "\(:[^=]\|[;,]\)"
syn match murphiSpecial "[()\[\]]"
" Double equal sign is a common error: use one equal sign for equality testing.
syn match murphiError "==[^>]"he=e-1
" Double && and || are errors.
syn match murphiError "&&\|||"
" Strings. This is defined so late so that it overrides previous matches.
syn region murphiString start=+"+ end=+"+
" Comments. This is defined so late so that it overrides previous matches.
syn region murphiComment start="--" end="$" contains=murphiTodo
syn region murphiComment start="/\*" end="\*/" contains=murphiTodo
" Link the rules to some groups.
highlight link murphiComment Comment
highlight link murphiString String
highlight link murphiNumber Number
highlight link murphiBoolean Boolean
highlight link murphiIdentifier Identifier
highlight link murphiFunction Function
highlight link murphiStatement Statement
highlight link murphiConditional Conditional
highlight link murphiRepeat Repeat
highlight link murphiLabel Label
highlight link murphiOperator Operator
highlight link murphiKeyword Keyword
highlight link murphiType Type
highlight link murphiStructure Structure
highlight link murphiSpecial Special
highlight link murphiDelimiter Delimiter
highlight link murphiError Error
highlight link murphiTodo Todo
let b:current_syntax = "murphi"

View File

@@ -1,15 +1,15 @@
" Vim syntax file
" Language: php PHP 3/4/5/7
" Maintainer: Jason Woofenden <jason@jasonwoof.com>
" Last Change: Jun 09, 2017
" Last Change: Jul 14, 2017
" URL: https://jasonwoof.com/gitweb/?p=vim-syntax.git;a=blob;f=php.vim;hb=HEAD
" Former Maintainers: Peter Hodge <toomuchphp-vim@yahoo.com>
" Debian VIM Maintainers <pkg-vim-maintainers@lists.alioth.debian.org>
"
" Note: If you are using a colour terminal with dark background, you will probably find
" the 'elflord' colorscheme is much better for PHP's syntax than the default
" colourscheme, because elflord's colours will better highlight the break-points
" (Statements) in your code.
" Note: If you are using a colour terminal with dark background, you will
" probably find the 'elflord' colorscheme is much better for PHP's syntax
" than the default colourscheme, because elflord's colours will better
" highlight the break-points (Statements) in your code.
"
" Options:
" Set to anything to enable:
@@ -112,7 +112,7 @@ syn keyword phpCoreConstant E_ALL E_COMPILE_ERROR E_COMPILE_WARNING E_CORE_ERROR
syn case ignore
syn keyword phpConstant __LINE__ __FILE__ __FUNCTION__ __METHOD__ __CLASS__ __DIR__ __NAMESPACE__ contained
syn keyword phpConstant __LINE__ __FILE__ __FUNCTION__ __METHOD__ __CLASS__ __DIR__ __NAMESPACE__ __TRAIT__ contained
" Function and Methods ripped from php_manual_de.tar.gz Jan 2003
@@ -255,13 +255,13 @@ syn keyword phpRepeat as do endfor endforeach endwhile for foreach while contai
syn keyword phpLabel case default switch contained
" Statement
syn keyword phpStatement return break continue exit goto contained
syn keyword phpStatement return break continue exit goto yield contained
" Keyword
syn keyword phpKeyword var const contained
" Type
syn keyword phpType bool boolean int integer real double float string array object NULL contained
syn keyword phpType bool boolean int integer real double float string array object NULL callable iterable contained
" Structure
syn keyword phpStructure namespace extends implements instanceof parent self contained
@@ -320,7 +320,6 @@ syn match phpMethodsVar "->\h\w*" contained contains=phpMethods,phpMemberSelecto
" Include
syn keyword phpInclude include require include_once require_once use contained
" Peter Hodge - added 'clone' keyword
" Define
syn keyword phpDefine new clone contained
@@ -441,38 +440,32 @@ if exists("php_folding") && php_folding==1
syn keyword phpFCKeyword function contained
syn keyword phpStorageClass global contained
syn match phpDefine "\(\s\|^\)\(abstract\s\+\|final\s\+\|private\s\+\|protected\s\+\|public\s\+\|static\s\+\)*function\(\s\+.*[;}]\)\@=" contained contains=phpSCKeyword
syn match phpStructure "\(\s\|^\)\(abstract\s\+\|final\s\+\)*class\(\s\+.*}\)\@=" contained
syn match phpStructure "\(\s\|^\)\(abstract\s\+\|final\s\+\)*\(trait\|class\)\(\s\+.*}\)\@=" contained
syn match phpStructure "\(\s\|^\)interface\(\s\+.*}\)\@=" contained
syn match phpException "\(\s\|^\)try\(\s\+.*}\)\@=" contained
syn match phpException "\(\s\|^\)catch\(\s\+.*}\)\@=" contained
syn match phpException "\(\s\|^\)finally\(\s\+.*}\)\@=" contained
set foldmethod=syntax
syn region phpFoldHtmlInside matchgroup=Delimiter start="?>" end="<?\(php\)\=" contained transparent contains=@htmlTop
syn region phpFoldFunction matchgroup=Storageclass start="^\z(\s*\)\(abstract\s\+\|final\s\+\|private\s\+\|protected\s\+\|public\s\+\|static\s\+\)*function\s\([^};]*$\)\@="rs=e-9 matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldHtmlInside,phpFCKeyword contained transparent fold extend
syn region phpFoldFunction matchgroup=Define start="^function\s\([^};]*$\)\@=" matchgroup=Delimiter end="^}" contains=@phpClFunction,phpFoldHtmlInside contained transparent fold extend
syn region phpFoldClass matchgroup=Structure start="^\z(\s*\)\(abstract\s\+\|final\s\+\)*class\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction,phpSCKeyword contained transparent fold extend
syn region phpFoldClass matchgroup=Structure start="^\z(\s*\)\(abstract\s\+\|final\s\+\)*\(trait\|class\)\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction,phpSCKeyword contained transparent fold extend
syn region phpFoldInterface matchgroup=Structure start="^\z(\s*\)interface\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction contained transparent fold extend
syn region phpFoldCatch matchgroup=Exception start="^\z(\s*\)catch\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction contained transparent fold extend
syn region phpFoldTry matchgroup=Exception start="^\z(\s*\)try\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction contained transparent fold extend
elseif exists("php_folding") && php_folding==2
else
syn keyword phpDefine function contained
syn keyword phpStructure abstract class interface contained
syn keyword phpException catch throw try contained
syn keyword phpStructure abstract class trait interface contained
syn keyword phpException catch throw try finally contained
syn keyword phpStorageClass final global private protected public static contained
if exists("php_folding") && php_folding==2
set foldmethod=syntax
syn region phpFoldHtmlInside matchgroup=Delimiter start="?>" end="<?\(php\)\=" contained transparent contains=@htmlTop
syn region phpParent matchgroup=Delimiter start="{" end="}" contained contains=@phpClFunction,phpFoldHtmlInside transparent fold
else
syn keyword phpDefine function contained
syn keyword phpStructure abstract class interface contained
syn keyword phpException catch throw try contained
syn keyword phpStorageClass final global private protected public static contained
endif
endif
" TODO: fold on "trait". For now just make sure it gets colored:
syn keyword phpStructure trait
" ================================================================
" Peter Hodge - June 9, 2006
" Some of these changes (highlighting isset/unset/echo etc) are not so

View File

@@ -1,7 +1,7 @@
" SiSU Vim syntax file
" SiSU Maintainer: Ralph Amissah <ralph.amissah@gmail.com>
" SiSU Markup: SiSU (sisu-5.6.7)
" Last Change: 2014-09-14
" Last Change: 2017 Jun 22
" URL: <http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=blob;f=data/sisu/conf/editor-syntax-etc/vim/syntax/sisu.vim;hb=HEAD>
" <http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=blob_plain;f=data/sisu/conf/editor-syntax-etc/vim/syntax/sisu.vim;hb=HEAD>
"(originally looked at Ruby Vim by Mirko Nasato)
@@ -102,7 +102,7 @@ syn region sisu_content_alt contains=sisu_strikeout,sisu_number,sisu_bold,sisu_c
syn region sisu_content_alt contains=sisu_strikeout,sisu_number,sisu_bold,sisu_control,sisu_identifier,sisu_error matchgroup=sisu_contain start="^```\s\+table" end="^```\(\s\|$\)"
syn region sisu_content_alt contains=sisu_strikeout,sisu_number,sisu_bold,sisu_control,sisu_identifier,sisu_error matchgroup=sisu_contain start="^{\(t\|table\)\(\~h\)\?\(\sc[0-9]\+;\)\?[0-9; ]*}" end="\n$"
" block, group, poem, alt
syn region sisu_content_alt contains=sisu_mark_endnote,sisu_content_endnote,sisu_link,sisu_mark,sisu_strikeout,sisu_number,sisu_control,sisu_identifier,sisu_error matchgroup=sisu_contain start="^\(block\|group\|poem\|alt\){" end="^}\1"
syn region sisu_content_alt contains=sisu_mark_endnote,sisu_content_endnote,sisu_link,sisu_mark,sisu_strikeout,sisu_number,sisu_control,sisu_identifier,sisu_error matchgroup=sisu_contain start="^\z(block\|group\|poem\|alt\){" end="^}\z1"
syn region sisu_content_alt contains=sisu_mark_endnote,sisu_content_endnote,sisu_link,sisu_mark,sisu_strikeout,sisu_number,sisu_control,sisu_identifier,sisu_error matchgroup=sisu_contain start="^```\s\+\(block\|group\|poem\|alt\)" end="^```\(\s\|$\)"
" box
syn region sisu_content_alt contains=sisu_mark_endnote,sisu_content_endnote,sisu_link,sisu_mark,sisu_strikeout,sisu_number,sisu_control,sisu_identifier,sisu_error matchgroup=sisu_contain start="^box\(\.[a-z]\+\)\?{" end="^}box"

View File

@@ -3,6 +3,7 @@
" http://www.unicode.org/Public/5.1.0/ucd/UCD.html
" For the other files see the header.
"
" Might need to update the URL to the emoji-data.txt
" Usage: Vim -S <this-file>
"
" Author: Bram Moolenaar
@@ -382,8 +383,9 @@ let s:ambitable = []
call BuildWidthTable('A', 'ambiguous')
" Edit the emoji text file. Requires the netrw plugin.
edit http://www.unicode.org/Public/emoji/3.0/emoji-data.txt
edit http://unicode.org/Public/emoji/5.0/emoji-data.txt
"edit http://www.unicode.org/Public/emoji/latest/emoji-data.txt
" Build the emoji table. Ver. 1.0 - 6.0
" Must come after the "ambiguous" table
call BuildEmojiTable('; Emoji\s\+# [1-6]\.[0-9]', 'emoji')
call BuildEmojiTable('; Emoji\s\+#\s\+\d\+\.\d', 'emoji')

View File

@@ -88,7 +88,7 @@ NOTE : :q! <Entrée> annule tous les changements que vous avez faits. Dans
4. Répétez les étapes 2 à 4 jusqu'à ce que la phrase soit correcte.
---> La vvache à sautéé au-ddessus dde la luune.
---> La vvache a sautéé au-ddessus dde la luune.
5. Maintenant que la ligne est correcte, passez à la Leçon 1.4.
@@ -1034,5 +1034,5 @@ NOTE : Le complètement fonctionne pour de nombreuses commandes. Essayez
Dernières mises à jour par Dominique Pellé.
E-mail : dominique.pelle@gmail.com
Last Change : 2017 Jan 16
Last Change : 2017 Jun 30
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -904,7 +904,7 @@ NOTA: Se quiser ignorar a diferen
:e $VIM/_vimrc para MS-Windows
2. Agora, leia o conte<74>do do arquivo "vimrc" de exemplo:
:r $VIM/vimrc_example.vim
:r $VIMRUNTIME/vimrc_example.vim
3. Salve o arquivo com:
:w

View File

@@ -904,7 +904,7 @@ NOTA: Se quiser ignorar a diferença entre maiúsculas e minúsculas em apenas
:e $VIM/_vimrc para MS-Windows
2. Agora, leia o conteúdo do arquivo "vimrc" de exemplo:
:r $VIM/vimrc_example.vim
:r $VIMRUNTIME/vimrc_example.vim
3. Salve o arquivo com:
:w

View File

@@ -482,6 +482,11 @@ CClink = $(CC)
# Uncomment this when you do not want inter process communication.
#CONF_OPT_CHANNEL = --disable-channel
# TERMINAL - Terminal emulator support, :terminal command. Requires the
# channel feature.
# Uncomment this when you want terminal emulator support.
#CONF_OPT_TERMINAL = --enable-terminal
# MULTIBYTE - To edit multi-byte characters.
# Uncomment this when you want to edit a multibyte language.
# It's automatically enabled with normal features, GTK or IME support.
@@ -598,6 +603,9 @@ CClink = $(CC)
# Use this with GCC to check for mistakes, unused arguments, etc.
#CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wunreachable-code -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
# Add -Wpedantic to find // comments and other C99 constructs.
# Better disable Perl and Python to avoid a lot of warnings.
#CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
#CFLAGS = -g -O2 -Wall -Wextra -Wmissing-prototypes -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -DU_DEBUG
#PYTHON_CFLAGS_EXTRA = -Wno-missing-field-initializers
#MZSCHEME_CFLAGS_EXTRA = -Wno-unreachable-code -Wno-unused-parameter
@@ -1371,6 +1379,13 @@ ALL_GUI_PRO = gui.pro gui_gtk.pro gui_motif.pro gui_xmdlg.pro gui_athena.pro gu
# }}}
TERM_DEPS = \
libvterm/include/vterm.h \
libvterm/include/vterm_keycodes.h \
libvterm/src/rect.h \
libvterm/src/utf8.h \
libvterm/src/vterm_internal.h
### Command to create dependencies based on #include "..."
### prototype headers are ignored due to -DPROTO, system
### headers #include <...> are ignored if we use the -MM option, as
@@ -1560,6 +1575,7 @@ BASIC_SRC = \
syntax.c \
tag.c \
term.c \
terminal.c \
ui.c \
undo.c \
userfunc.c \
@@ -1569,6 +1585,7 @@ BASIC_SRC = \
SRC = $(BASIC_SRC) \
$(GUI_SRC) \
$(TERM_SRC) \
$(HANGULIN_SRC) \
$(LUA_SRC) \
$(MZSCHEME_SRC) \
@@ -1610,7 +1627,7 @@ ALL_SRC = $(BASIC_SRC) $(ALL_GUI_SRC) $(UNITTEST_SRC) $(EXTRA_SRC)
LINT_SRC = $(BASIC_SRC) $(GUI_SRC) $(HANGULIN_SRC) \
$(PYTHON_SRC) $(PYTHON3_SRC) $(TCL_SRC) \
$(WORKSHOP_SRC) $(WSDEBUG_SRC) \
$(NETBEANS_SRC) $(CHANNEL_SRC)
$(NETBEANS_SRC) $(CHANNEL_SRC) $(TERM_SRC)
#LINT_SRC = $(SRC)
#LINT_SRC = $(ALL_SRC)
#LINT_SRC = $(BASIC_SRC)
@@ -1665,12 +1682,14 @@ OBJ_COMMON = \
objects/syntax.o \
objects/tag.o \
objects/term.o \
objects/terminal.o \
objects/ui.o \
objects/undo.o \
objects/userfunc.o \
objects/version.o \
objects/window.o \
$(GUI_OBJ) \
$(TERM_OBJ) \
$(LUA_OBJ) \
$(MZSCHEME_OBJ) \
$(PERL_OBJ) \
@@ -1795,6 +1814,7 @@ PRO_AUTO = \
syntax.pro \
tag.pro \
term.pro \
terminal.pro \
termlib.pro \
ui.pro \
undo.pro \
@@ -1848,7 +1868,7 @@ config auto/config.mk: auto/configure config.mk.in config.h.in
$(CONF_OPT_OUTPUT) $(CONF_OPT_GPM) $(CONF_OPT_WORKSHOP) \
$(CONF_OPT_FEAT) $(CONF_TERM_LIB) \
$(CONF_OPT_COMPBY) $(CONF_OPT_ACL) $(CONF_OPT_NETBEANS) \
$(CONF_OPT_CHANNEL) \
$(CONF_OPT_CHANNEL) $(CONF_OPT_TERMINAL) \
$(CONF_ARGS) $(CONF_OPT_MZSCHEME) $(CONF_OPT_PLTHOME) \
$(CONF_OPT_LUA) $(CONF_OPT_LUA_PREFIX) \
$(CONF_OPT_SYSMOUSE); \
@@ -2072,25 +2092,23 @@ test1 \
test_autoformat_join \
test_changelist \
test_close_count \
test_comparators \
test_erasebackword \
test_eval \
test_fixeol \
test_getcwd \
test_insertcount \
test_listchars \
test_search_mbyte \
test_wordcount \
test3 test4 test5 test6 test7 test8 test9 \
test11 test12 test14 test15 test17 test18 test19 \
test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 \
test20 test21 test22 test25 test27 test28 test29 \
test30 test31 test32 test33 test34 test36 test37 test38 test39 \
test40 test41 test42 test43 test44 test45 test48 test49 \
test50 test51 test52 test53 test54 test55 test56 test57 test58 test59 \
test60 test64 test66 test67 test68 test69 \
test70 test72 test73 test74 test75 test77 test78 test79 \
test80 test82 test83 test84 test85 test86 test87 test88 \
test90 test91 test94 test95 test97 test98 test99 \
test50 test51 test52 test53 test54 test55 test56 test57 test59 \
test60 test64 test66 test68 test69 \
test70 test72 test73 test74 test77 test78 test79 \
test80 test83 test84 test85 test86 test87 test88 \
test91 test94 test95 test98 test99 \
test100 test101 test103 test104 test107 test108:
cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
@@ -2114,6 +2132,7 @@ test_arglist \
test_clientserver \
test_cmdline \
test_command_count \
test_comparators \
test_crypt \
test_cscope \
test_cursor_func \
@@ -2122,9 +2141,12 @@ test_arglist \
test_digraph \
test_display \
test_edit \
test_escaped_glob \
test_ex_undo \
test_ex_z \
test_exec_while_if \
test_execute_func \
test_exists_autocmd \
test_expand \
test_expand_dllpath \
test_expr \
@@ -2143,6 +2165,7 @@ test_arglist \
test_fold \
test_functions \
test_ga \
test_getcwd \
test_gf \
test_glob2regpat \
test_global \
@@ -2171,6 +2194,7 @@ test_arglist \
test_lua \
test_makeencoding \
test_man \
test_maparg \
test_mapping \
test_marks \
test_match \
@@ -2189,6 +2213,7 @@ test_arglist \
test_partial \
test_paste \
test_perl \
test_plus_arg_edit \
test_popup \
test_profile \
test_put \
@@ -2199,6 +2224,7 @@ test_arglist \
test_quickfix \
test_quotestar \
test_recover \
test_regex_char_classes \
test_regexp_latin \
test_regexp_utf8 \
test_reltime \
@@ -2207,6 +2233,7 @@ test_arglist \
test_search \
test_searchpos \
test_set \
test_sha256 \
test_signs \
test_smartindent \
test_sort \
@@ -2233,6 +2260,7 @@ test_arglist \
test_unlet \
test_usercommands \
test_utf8 \
test_utf8_comparisons \
test_viminfo \
test_vimscript \
test_visual \
@@ -2788,7 +2816,7 @@ SHADOWDIR = shadow
shadow: runtime pixmaps
$(MKDIR_P) $(SHADOWDIR)
cd $(SHADOWDIR); ln -s ../*.[chm] ../*.in ../*.sh ../*.xs ../*.xbm ../gui_gtk_res.xml ../toolcheck ../proto ../vimtutor ../gvimtutor ../install-sh .
cd $(SHADOWDIR); ln -s ../*.[chm] ../*.in ../*.sh ../*.xs ../*.xbm ../gui_gtk_res.xml ../toolcheck ../proto ../libvterm ../vimtutor ../gvimtutor ../install-sh .
mkdir $(SHADOWDIR)/auto
cd $(SHADOWDIR)/auto; ln -s ../../auto/configure .
$(MKDIR_P) $(SHADOWDIR)/po
@@ -3226,6 +3254,9 @@ objects/tag.o: tag.c
objects/term.o: term.c
$(CCC) -o $@ term.c
objects/terminal.o: terminal.c $(TERM_DEPS)
$(CCC) -o $@ terminal.c
objects/ui.o: ui.c
$(CCC) -o $@ ui.c
@@ -3253,6 +3284,34 @@ objects/channel.o: channel.c
Makefile:
@echo The name of the makefile MUST be "Makefile" (with capital M)!!!!
CCCTERM = $(CCC) -Ilibvterm/include -DINLINE="" -DVSNPRINTF=vim_vsnprintf
objects/term_encoding.o: libvterm/src/encoding.c $(TERM_DEPS)
$(CCCTERM) -o $@ libvterm/src/encoding.c
objects/term_keyboard.o: libvterm/src/keyboard.c $(TERM_DEPS)
$(CCCTERM) -o $@ libvterm/src/keyboard.c
objects/term_mouse.o: libvterm/src/mouse.c $(TERM_DEPS)
$(CCCTERM) -o $@ libvterm/src/mouse.c
objects/term_parser.o: libvterm/src/parser.c $(TERM_DEPS)
$(CCCTERM) -o $@ libvterm/src/parser.c
objects/term_pen.o: libvterm/src/pen.c $(TERM_DEPS)
$(CCCTERM) -o $@ libvterm/src/pen.c
objects/term_screen.o: libvterm/src/screen.c $(TERM_DEPS)
$(CCCTERM) -o $@ libvterm/src/screen.c
objects/term_state.o: libvterm/src/state.c $(TERM_DEPS)
$(CCCTERM) -o $@ libvterm/src/state.c
objects/term_unicode.o: libvterm/src/unicode.c $(TERM_DEPS)
$(CCCTERM) -o $@ libvterm/src/unicode.c
objects/term_vterm.o: libvterm/src/vterm.c $(TERM_DEPS)
$(CCCTERM) -o $@ libvterm/src/vterm.c
###############################################################################
### MacOS X installation
###
@@ -3397,7 +3456,7 @@ objects/ex_cmds2.o: ex_cmds2.c vim.h auto/config.h feature.h os_unix.h \
objects/ex_docmd.o: ex_docmd.c vim.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
regexp.h gui.h gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h \
proto.h globals.h farsi.h arabic.h
proto.h globals.h farsi.h arabic.h ex_cmdidxs.h
objects/ex_eval.o: ex_eval.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
@@ -3501,7 +3560,7 @@ objects/option.o: option.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h
objects/os_unix.o: os_unix.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
globals.h farsi.h arabic.h if_mzsch.h os_unixx.h
globals.h farsi.h arabic.h os_unixx.h
objects/pathdef.o: auto/pathdef.c vim.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
regexp.h gui.h gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h \
@@ -3550,6 +3609,10 @@ objects/term.o: term.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
globals.h farsi.h arabic.h
objects/terminal.o: terminal.c vim.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
regexp.h gui.h gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h \
proto.h globals.h farsi.h arabic.h
objects/ui.o: ui.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h ascii.h \
keymap.h term.h macros.h option.h structs.h regexp.h gui.h gui_beval.h \
proto/gui_beval.pro alloc.h ex_cmds.h spell.h proto.h globals.h farsi.h \
@@ -3659,7 +3722,7 @@ objects/json_test.o: json_test.c main.c vim.h auto/config.h feature.h os_unix.h
objects/kword_test.o: kword_test.c main.c vim.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
regexp.h gui.h gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h \
proto.h globals.h farsi.h arabic.h charset.c mbyte.c
proto.h globals.h farsi.h arabic.h charset.c
objects/memfile_test.o: memfile_test.c main.c vim.h auto/config.h feature.h \
os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h \
structs.h regexp.h gui.h gui_beval.h proto/gui_beval.pro alloc.h \
@@ -3679,7 +3742,7 @@ objects/if_lua.o: if_lua.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h
objects/if_mzsch.o: if_mzsch.c vim.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
regexp.h gui.h gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h \
proto.h globals.h farsi.h arabic.h if_mzsch.h mzscheme_base.c
proto.h globals.h farsi.h arabic.h if_mzsch.h
objects/if_perl.o: auto/if_perl.c vim.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
regexp.h gui.h gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h \

33
src/auto/configure vendored
View File

@@ -655,6 +655,8 @@ X_PRE_LIBS
X_CFLAGS
XMKMF
xmkmfpath
TERM_OBJ
TERM_SRC
CHANNEL_OBJ
CHANNEL_SRC
NETBEANS_OBJ
@@ -814,6 +816,7 @@ enable_cscope
enable_workshop
enable_netbeans
enable_channel
enable_terminal
enable_multibyte
enable_hangulinput
enable_xim
@@ -1491,6 +1494,7 @@ Optional Features:
--enable-workshop Include Sun Visual Workshop support.
--disable-netbeans Disable NetBeans integration support.
--disable-channel Disable process communication support.
--enable-terminal Disable terminal emulation support.
--enable-multibyte Include multibyte editing support.
--enable-hangulinput Include Hangul input support.
--enable-xim Include XIM input support.
@@ -7464,6 +7468,35 @@ if test "$enable_channel" = "yes"; then
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-terminal argument" >&5
$as_echo_n "checking --enable-terminal argument... " >&6; }
# Check whether --enable-terminal was given.
if test "${enable_terminal+set}" = set; then :
enableval=$enable_terminal; enable_terminal="yes"
fi
if test "$enable_terminal" = "yes"; then
if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot use terminal emulator with tiny or small features" >&5
$as_echo "cannot use terminal emulator with tiny or small features" >&6; }
enable_terminal="no"
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
fi
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test "$enable_terminal" = "yes"; then
$as_echo "#define FEAT_TERMINAL 1" >>confdefs.h
TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/screen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c"
TERM_OBJ="objects/term_encoding.o objects/term_keyboard.o objects/term_mouse.o objects/term_parser.o objects/term_pen.o objects/term_screen.o objects/term_state.o objects/term_unicode.o objects/term_vterm.o"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-multibyte argument" >&5
$as_echo_n "checking --enable-multibyte argument... " >&6; }
# Check whether --enable-multibyte was given.

View File

@@ -372,7 +372,7 @@ open_buffer(
set_bufref(bufref_T *bufref, buf_T *buf)
{
bufref->br_buf = buf;
bufref->br_fnum = buf->b_fnum;
bufref->br_fnum = buf == NULL ? 0 : buf->b_fnum;
bufref->br_buf_free_count = buf_free_count;
}

View File

@@ -1438,6 +1438,7 @@ channel_write_in(channel_T *channel)
if (!bufref_valid(&in_part->ch_bufref) || buf->b_ml.ml_mfp == NULL)
{
/* buffer was wiped out or unloaded */
ch_log(channel, "input buffer has been wiped out");
in_part->ch_bufref.br_buf = NULL;
return;
}
@@ -2338,7 +2339,7 @@ append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, ch_part_T part)
int save_write_to = buffer->b_write_to_channel;
chanpart_T *ch_part = &channel->ch_part[part];
int save_p_ma = buffer->b_p_ma;
int empty = (buffer->b_ml.ml_flags & ML_EMPTY);
int empty = (buffer->b_ml.ml_flags & ML_EMPTY) ? 1 : 0;
if (!buffer->b_p_ma && !ch_part->ch_nomodifiable)
{
@@ -2359,13 +2360,14 @@ append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, ch_part_T part)
}
/* Append to the buffer */
ch_logn(channel, "appending line %d to buffer", (int)lnum + 1);
ch_logn(channel, "appending line %d to buffer", (int)lnum + 1 - empty);
buffer->b_p_ma = TRUE;
curbuf = buffer;
curwin->w_buffer = curbuf;
u_sync(TRUE);
/* ignore undo failure, undo is not very useful here */
ignored = u_save(lnum, lnum + 1 + (empty ? 1 : 0));
ignored = u_save(lnum - empty, lnum + 1);
if (empty)
{
@@ -2377,6 +2379,7 @@ append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, ch_part_T part)
ml_append(lnum, msg, 0, FALSE);
appended_lines_mark(lnum, 1L);
curbuf = save_curbuf;
curwin->w_buffer = curbuf;
if (ch_part->ch_nomodifiable)
buffer->b_p_ma = FALSE;
else
@@ -2483,9 +2486,11 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
}
buffer = ch_part->ch_bufref.br_buf;
if (buffer != NULL && !bufref_valid(&ch_part->ch_bufref))
if (buffer != NULL && (!bufref_valid(&ch_part->ch_bufref)
|| buffer->b_ml.ml_mfp == NULL))
{
/* buffer was wiped out */
/* buffer was wiped out or unloaded */
ch_logs(channel, "%s buffer has been wiped out", part_names[part]);
ch_part->ch_bufref.br_buf = NULL;
buffer = NULL;
}

View File

@@ -431,6 +431,9 @@
/* Define if you want to include process communication. */
#undef FEAT_JOB_CHANNEL
/* Define if you want to include terminal emulator support. */
#undef FEAT_TERMINAL
/* Define default global runtime path */
#undef RUNTIME_GLOBAL

View File

@@ -91,6 +91,8 @@ NETBEANS_SRC = @NETBEANS_SRC@
NETBEANS_OBJ = @NETBEANS_OBJ@
CHANNEL_SRC = @CHANNEL_SRC@
CHANNEL_OBJ = @CHANNEL_OBJ@
TERM_SRC = @TERM_SRC@
TERM_OBJ = @TERM_OBJ@
RUBY = @vi_cv_path_ruby@
RUBY_SRC = @RUBY_SRC@

View File

@@ -2028,6 +2028,28 @@ if test "$enable_channel" = "yes"; then
AC_SUBST(CHANNEL_OBJ)
fi
AC_MSG_CHECKING(--enable-terminal argument)
AC_ARG_ENABLE(terminal,
[ --enable-terminal Disable terminal emulation support.],
[enable_terminal="yes"], )
if test "$enable_terminal" = "yes"; then
if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
AC_MSG_RESULT([cannot use terminal emulator with tiny or small features])
enable_terminal="no"
else
AC_MSG_RESULT(yes)
fi
else
AC_MSG_RESULT(no)
fi
if test "$enable_terminal" = "yes"; then
AC_DEFINE(FEAT_TERMINAL)
TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/screen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c"
AC_SUBST(TERM_SRC)
TERM_OBJ="objects/term_encoding.o objects/term_keyboard.o objects/term_mouse.o objects/term_parser.o objects/term_pen.o objects/term_screen.o objects/term_state.o objects/term_unicode.o objects/term_vterm.o"
AC_SUBST(TERM_OBJ)
fi
AC_MSG_CHECKING(--enable-multibyte argument)
AC_ARG_ENABLE(multibyte,
[ --enable-multibyte Include multibyte editing support.], ,

View File

@@ -4308,9 +4308,17 @@ ins_compl_get_exp(pos_T *ini)
{
ins_buf = curbuf;
first_match_pos = *ini;
/* So that ^N can match word immediately after cursor */
if (ctrl_x_mode == 0)
dec(&first_match_pos);
/* Move the cursor back one character so that ^N can match the
* word immediately after the cursor. */
if (ctrl_x_mode == 0 && dec(&first_match_pos) < 0)
{
/* Move the cursor to after the last character in the
* buffer, so that word at start of buffer is found
* correctly. */
first_match_pos.lnum = ins_buf->b_ml.ml_line_count;
first_match_pos.col =
(colnr_T)STRLEN(ml_get(first_match_pos.lnum));
}
last_match_pos = first_match_pos;
type = 0;
@@ -7321,7 +7329,9 @@ oneleft(void)
#ifdef FEAT_VIRTUALEDIT
if (virtual_active())
{
# ifdef FEAT_LINEBREAK
int width;
# endif
int v = getviscol();
if (v == 0)

View File

@@ -3191,7 +3191,11 @@ f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
insert ? 0 : typebuf.tb_len, !typed, FALSE);
vim_free(keys_esc);
if (vgetc_busy)
if (vgetc_busy
#ifdef FEAT_TIMERS
|| timer_busy
#endif
)
typebuf_was_filled = TRUE;
if (execute)
{
@@ -5866,6 +5870,9 @@ f_has(typval_T *argvars, typval_T *rettv)
#ifdef FEAT_TERMGUICOLORS
"termguicolors",
#endif
#ifdef FEAT_TERMINAL
"terminal",
#endif
#ifdef TERMINFO
"terminfo",
#endif
@@ -8036,14 +8043,15 @@ f_printf(typval_T *argvars, typval_T *rettv)
/* Get the required length, allocate the buffer and do it for real. */
did_emsg = FALSE;
fmt = (char *)get_tv_string_buf(&argvars[0], buf);
len = vim_vsnprintf(NULL, 0, fmt, ap, argvars + 1);
len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
if (!did_emsg)
{
s = alloc(len + 1);
if (s != NULL)
{
rettv->vval.v_string = s;
(void)vim_vsnprintf((char *)s, len + 1, fmt, ap, argvars + 1);
(void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
ap, argvars + 1);
}
}
did_emsg |= saved_did_emsg;
@@ -11841,8 +11849,8 @@ f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
{
cchar = syn_get_sub_char();
if (cchar == NUL && curwin->w_p_cole == 1 && lcs_conceal != NUL)
cchar = lcs_conceal;
if (cchar == NUL && curwin->w_p_cole == 1)
cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
if (cchar != NUL)
{
# ifdef FEAT_MBYTE
@@ -12394,6 +12402,7 @@ f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
{
char_u *name = (char_u *)"";
int val;
static int save_starting = -1;
if (argvars[0].v_type != VAR_STRING
|| (argvars[1].v_type) != VAR_NUMBER)
@@ -12407,10 +12416,29 @@ f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
disable_redraw_for_testing = val;
else if (STRCMP(name, (char_u *)"char_avail") == 0)
disable_char_avail_for_testing = val;
else if (STRCMP(name, (char_u *)"starting") == 0)
{
if (val)
{
if (save_starting < 0)
save_starting = starting;
starting = 0;
}
else
{
starting = save_starting;
save_starting = -1;
}
}
else if (STRCMP(name, (char_u *)"ALL") == 0)
{
disable_char_avail_for_testing = FALSE;
disable_redraw_for_testing = FALSE;
if (save_starting >= 0)
{
starting = save_starting;
save_starting = -1;
}
}
else
EMSG2(_(e_invarg2), name);

View File

@@ -25,12 +25,12 @@ static const unsigned short cmdidxs1[26] =
/* r */ 351,
/* s */ 370,
/* t */ 437,
/* u */ 472,
/* v */ 483,
/* w */ 501,
/* x */ 516,
/* y */ 525,
/* z */ 526
/* u */ 473,
/* v */ 484,
/* w */ 502,
/* x */ 517,
/* y */ 526,
/* z */ 527
};
/*
@@ -60,7 +60,7 @@ static const unsigned char cmdidxs2[26][26] =
/* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 18, 0, 0, 0, 0 },
/* s */ { 2, 6, 15, 0, 18, 22, 0, 24, 25, 0, 0, 28, 30, 34, 38, 40, 0, 48, 0, 49, 0, 61, 62, 0, 63, 0 },
/* t */ { 2, 0, 19, 0, 22, 23, 0, 24, 0, 25, 0, 26, 27, 28, 29, 30, 0, 31, 33, 0, 34, 0, 0, 0, 0, 0 },
/* t */ { 2, 0, 19, 0, 22, 24, 0, 25, 0, 26, 0, 27, 28, 29, 30, 31, 0, 32, 34, 0, 35, 0, 0, 0, 0, 0 },
/* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/* v */ { 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 9, 12, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0 },
/* w */ { 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 8, 0, 9, 10, 0, 12, 0, 13, 14, 0, 0, 0, 0 },
@@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] =
/* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
static const int command_count = 539;
static const int command_count = 540;

View File

@@ -1743,7 +1743,7 @@ static int viminfo_errcnt;
no_viminfo(void)
{
/* "vim -i NONE" does not read or write a viminfo file */
return (use_viminfo != NULL && STRCMP(use_viminfo, "NONE") == 0);
return STRCMP(p_viminfofile, "NONE") == 0;
}
/*
@@ -2093,8 +2093,8 @@ viminfo_filename(char_u *file)
{
if (file == NULL || *file == NUL)
{
if (use_viminfo != NULL)
file = use_viminfo;
if (*p_viminfofile != NUL)
file = p_viminfofile;
else if ((file = find_viminfo_parameter('n')) == NULL || *file == NUL)
{
#ifdef VIMINFO_FILE2
@@ -3968,8 +3968,8 @@ do_ecmd(
* <VN> We could instead free the synblock
* and re-attach to buffer, perhaps.
*/
if (curwin->w_buffer != NULL
&& curwin->w_s == &(curwin->w_buffer->b_s))
if (curwin->w_buffer == NULL
|| curwin->w_s == &(curwin->w_buffer->b_s))
curwin->w_s = &(buf->b_s);
#endif
curwin->w_buffer = buf;
@@ -6832,8 +6832,15 @@ fix_help_buffer(void)
char_u *rt;
int mustfree;
/* set filetype to "help". */
#ifdef FEAT_AUTOCMD
/* Set filetype to "help" if still needed. */
if (STRCMP(curbuf->b_p_ft, "help") != 0)
{
++curbuf_lock;
set_option_value((char_u *)"ft", 0L, (char_u *)"help", OPT_LOCAL);
--curbuf_lock;
}
#endif
#ifdef FEAT_SYN_HL
if (!syntax_present(curwin))

View File

@@ -51,7 +51,9 @@
#define BUFUNL 0x20000L /* accepts unlisted buffer too */
#define ARGOPT 0x40000L /* allow "++opt=val" argument */
#define SBOXOK 0x80000L /* allowed in the sandbox */
#define CMDWIN 0x100000L /* allowed in cmdline window */
#define CMDWIN 0x100000L /* allowed in cmdline window; when missing
* disallows editing another buffer when
* curbuf_lock is set */
#define MODIFY 0x200000L /* forbidden in non-'modifiable' buffer */
#define EXFLAGS 0x400000L /* allow flags after count in argument */
#define FILES (XFILE | EXTRA) /* multiple extra files allowed */
@@ -426,7 +428,7 @@ EX(CMD_delcommand, "delcommand", ex_delcommand,
NEEDARG|WORD1|TRLBAR|CMDWIN,
ADDR_LINES),
EX(CMD_delfunction, "delfunction", ex_delfunction,
NEEDARG|WORD1|CMDWIN,
BANG|NEEDARG|WORD1|CMDWIN,
ADDR_LINES),
EX(CMD_display, "display", ex_display,
EXTRA|NOTRLCOM|TRLBAR|SBOXOK|CMDWIN,
@@ -1176,7 +1178,7 @@ EX(CMD_registers, "registers", ex_display,
EXTRA|NOTRLCOM|TRLBAR|CMDWIN,
ADDR_LINES),
EX(CMD_resize, "resize", ex_resize,
RANGE|NOTADR|TRLBAR|WORD1,
RANGE|NOTADR|TRLBAR|WORD1|CMDWIN,
ADDR_LINES),
EX(CMD_retab, "retab", ex_retab,
TRLBAR|RANGE|WHOLEFOLD|DFLALL|BANG|WORD1|CMDWIN|MODIFY,
@@ -1481,6 +1483,9 @@ EX(CMD_tclfile, "tclfile", ex_tclfile,
EX(CMD_tearoff, "tearoff", ex_tearoff,
NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN,
ADDR_LINES),
EX(CMD_terminal, "terminal", ex_terminal,
RANGE|NOTADR|EXTRA|TRLBAR|CMDWIN,
ADDR_OTHER),
EX(CMD_tfirst, "tfirst", ex_tag,
RANGE|NOTADR|BANG|TRLBAR|ZEROR,
ADDR_LINES),
@@ -1620,7 +1625,7 @@ EX(CMD_winsize, "winsize", ex_winsize,
EXTRA|NEEDARG|TRLBAR,
ADDR_LINES),
EX(CMD_wincmd, "wincmd", ex_wincmd,
NEEDARG|WORD1|RANGE|NOTADR,
NEEDARG|WORD1|RANGE|NOTADR|CMDWIN,
ADDR_WINDOWS),
EX(CMD_windo, "windo", ex_listdo,
NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,

View File

@@ -1183,6 +1183,7 @@ timer_callback(timer_T *timer)
/*
* Call timers that are due.
* Return the time in msec until the next timer is due.
* Returns -1 if there are no pending timers.
*/
long
check_due_timer(void)
@@ -1196,7 +1197,13 @@ check_due_timer(void)
long current_id = last_timer_id;
# ifdef WIN3264
LARGE_INTEGER fr;
# endif
/* Don't run any timers while exiting or dealing with an error. */
if (exiting || aborting())
return next_due;
# ifdef WIN3264
QueryPerformanceFrequency(&fr);
# endif
profile_start(&now);
@@ -1209,15 +1216,35 @@ check_due_timer(void)
this_due = GET_TIMEDIFF(timer, now);
if (this_due <= 1)
{
int save_timer_busy = timer_busy;
int save_vgetc_busy = vgetc_busy;
int did_emsg_save = did_emsg;
int called_emsg_save = called_emsg;
int did_throw_save = did_throw;
timer_busy = timer_busy > 0 || vgetc_busy > 0;
vgetc_busy = 0;
called_emsg = FALSE;
timer->tr_firing = TRUE;
timer_callback(timer);
timer->tr_firing = FALSE;
timer_next = timer->tr_next;
did_one = TRUE;
timer_busy = save_timer_busy;
vgetc_busy = save_vgetc_busy;
if (called_emsg)
{
++timer->tr_emsg_count;
if (!did_throw_save && did_throw && current_exception != NULL)
discard_current_exception();
}
did_emsg = did_emsg_save;
called_emsg = called_emsg_save;
/* Only fire the timer again if it repeats and stop_timer() wasn't
* called while inside the callback (tr_id == -1). */
if (timer->tr_repeat != 0 && timer->tr_id != -1)
if (timer->tr_repeat != 0 && timer->tr_id != -1
&& timer->tr_emsg_count < 3)
{
profile_setlimit(timer->tr_interval, &timer->tr_due);
this_due = GET_TIMEDIFF(timer, now);
@@ -3278,19 +3305,6 @@ source_callback(char_u *fname, void *cookie UNUSED)
(void)do_source(fname, FALSE, DOSO_NONE);
}
/*
* Source the file "name" from all directories in 'runtimepath'.
* "name" can contain wildcards.
* When "flags" has DIP_ALL: source all files, otherwise only the first one.
*
* return FAIL when no file could be sourced, OK otherwise.
*/
int
source_runtime(char_u *name, int flags)
{
return do_in_runtimepath(name, flags, source_callback, NULL);
}
/*
* Find the file "name" in all directories in "path" and invoke
* "callback(fname, cookie)".
@@ -3428,18 +3442,19 @@ do_in_path(
}
/*
* Find "name" in 'runtimepath'. When found, invoke the callback function for
* Find "name" in "path". When found, invoke the callback function for
* it: callback(fname, "cookie")
* When "flags" has DIP_ALL repeat for all matches, otherwise only the first
* one is used.
* Returns OK when at least one match found, FAIL otherwise.
*
* If "name" is NULL calls callback for each entry in runtimepath. Cookie is
* If "name" is NULL calls callback for each entry in "path". Cookie is
* passed by reference in this case, setting it to NULL indicates that callback
* has done its job.
*/
int
do_in_runtimepath(
static int
do_in_path_and_pp(
char_u *path,
char_u *name,
int flags,
void (*callback)(char_u *fname, void *ck),
@@ -3452,7 +3467,7 @@ do_in_runtimepath(
char *opt_dir = "pack/*/opt/*/%s";
if ((flags & DIP_NORTP) == 0)
done = do_in_path(p_rtp, name, flags, callback, cookie);
done = do_in_path(path, name, flags, callback, cookie);
if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
{
@@ -3479,6 +3494,42 @@ do_in_runtimepath(
return done;
}
/*
* Just like do_in_path_and_pp(), using 'runtimepath' for "path".
*/
int
do_in_runtimepath(
char_u *name,
int flags,
void (*callback)(char_u *fname, void *ck),
void *cookie)
{
return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
}
/*
* Source the file "name" from all directories in 'runtimepath'.
* "name" can contain wildcards.
* When "flags" has DIP_ALL: source all files, otherwise only the first one.
*
* return FAIL when no file could be sourced, OK otherwise.
*/
int
source_runtime(char_u *name, int flags)
{
return source_in_path(p_rtp, name, flags);
}
/*
* Just like source_runtime(), but use "path" instead of 'runtimepath'.
*/
int
source_in_path(char_u *path, char_u *name, int flags)
{
return do_in_path_and_pp(path, name, flags, source_callback, NULL);
}
/*
* Expand wildcards in "pat" and invoke do_source() for each match.
*/

View File

@@ -488,6 +488,9 @@ static void ex_folddo(exarg_T *eap);
#ifndef FEAT_PROFILE
# define ex_profile ex_ni
#endif
#ifndef FEAT_TERMINAL
# define ex_terminal ex_ni
#endif
/*
* Declare cmdnames[].
@@ -2370,7 +2373,8 @@ do_one_cmd(
goto doend;
}
/* Check for wrong commands. */
if (*p == '!' && ea.cmd[1] == 0151 && ea.cmd[0] == 78)
if (*p == '!' && ea.cmd[1] == 0151 && ea.cmd[0] == 78
&& !IS_USER_CMDIDX(ea.cmdidx))
{
errormsg = uc_fun_cmd();
goto doend;
@@ -7267,8 +7271,11 @@ ex_quit(exarg_T *eap)
apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf);
/* Refuse to quit when locked or when the buffer in the last window is
* being closed (can only happen in autocommands). */
if (curbuf_locked() || (wp->w_buffer->b_nwindows == 1
&& wp->w_buffer->b_locked > 0))
if (curbuf_locked()
# ifdef FEAT_WINDOWS
|| !win_valid(wp)
# endif
|| (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_locked > 0))
return;
#endif

View File

@@ -640,8 +640,11 @@ discard_exception(except_T *excp, int was_finished)
void
discard_current_exception(void)
{
if (current_exception != NULL)
{
discard_exception(current_exception, FALSE);
current_exception = NULL;
}
did_throw = FALSE;
need_rethrow = FALSE;
}
@@ -1978,7 +1981,10 @@ enter_cleanup(cleanup_T *csp)
* there is an extra instance for every call of do_cmdline(), anyway.
*/
if (did_throw || need_rethrow)
{
csp->exception = current_exception;
current_exception = NULL;
}
else
{
csp->exception = NULL;

View File

@@ -52,6 +52,8 @@ static int cmd_showtail; /* Only show path tail in lists ? */
static int new_cmdpos; /* position set by set_cmdline_pos() */
#endif
static int extra_char = NUL; /* extra character to display when redrawing
* the command line */
#ifdef FEAT_CMDHIST
typedef struct hist_entry
{
@@ -1173,12 +1175,14 @@ getcmdline(
dont_scroll = TRUE; /* disallow scrolling here */
#endif
putcmdline('"', TRUE);
extra_char = '"';
++no_mapping;
i = c = plain_vgetc(); /* CTRL-R <char> */
if (i == Ctrl_O)
i = Ctrl_R; /* CTRL-R CTRL-O == CTRL-R CTRL-R */
if (i == Ctrl_R)
c = plain_vgetc(); /* CTRL-R CTRL-R <char> */
extra_char = NUL;
--no_mapping;
#ifdef FEAT_EVAL
/*
@@ -1492,7 +1496,7 @@ getcmdline(
if (c != NUL)
{
if (c == firstc || vim_strchr((char_u *)(
p_magic ? "\\^$.*[" : "\\^$"), c)
p_magic ? "\\~^$.*[" : "\\^$"), c)
!= NULL)
{
/* put a backslash before special
@@ -1708,6 +1712,14 @@ getcmdline(
search_start = t;
(void)decl(&search_start);
}
else if (c == Ctrl_G && firstc == '?')
{
/* move just after the current match, so that
* when nv_search finishes the cursor will be
* put back on the match */
search_start = t;
(void)incl(&search_start);
}
if (LT_POS(t, search_start) && c == Ctrl_G)
{
/* wrap around */
@@ -1747,8 +1759,10 @@ getcmdline(
ignore_drag_release = TRUE;
#endif
putcmdline('^', TRUE);
extra_char = '^';
c = get_literal(); /* get next (two) character(s) */
do_abbr = FALSE; /* don't do abbreviation now */
extra_char = NUL;
#ifdef FEAT_MBYTE
/* may need to remove ^ when composing char was typed */
if (enc_utf8 && utf_iscomposing(c) && !cmd_silent)
@@ -1766,10 +1780,12 @@ getcmdline(
ignore_drag_release = TRUE;
#endif
putcmdline('?', TRUE);
extra_char = '?';
#ifdef USE_ON_FLY_SCROLL
dont_scroll = TRUE; /* disallow scrolling here */
#endif
c = get_digraph(TRUE);
extra_char = NUL;
if (c != NUL)
break;
@@ -3401,6 +3417,8 @@ redrawcmd(void)
msg_no_more = FALSE;
set_cmdspos_cursor();
if (extra_char != NUL)
putcmdline(extra_char, TRUE);
/*
* An emsg() before may have set msg_scroll. This is used in normal mode,
@@ -6878,6 +6896,8 @@ open_cmdwin(void)
# ifdef FEAT_AUTOCMD
/* Do execute autocommands for setting the filetype (load syntax). */
unblock_autocmds();
/* But don't allow switching to another buffer. */
++curbuf_lock;
# endif
/* Showing the prompt may have set need_wait_return, reset it. */
@@ -6893,6 +6913,9 @@ open_cmdwin(void)
}
set_option_value((char_u *)"ft", 0L, (char_u *)"vim", OPT_LOCAL);
}
# ifdef FEAT_AUTOCMD
--curbuf_lock;
# endif
/* Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin
* sets 'textwidth' to 78). */
@@ -7029,7 +7052,13 @@ open_cmdwin(void)
else
ccline.cmdbuff = vim_strsave(ml_get_curline());
if (ccline.cmdbuff == NULL)
{
ccline.cmdbuff = vim_strsave((char_u *)"");
ccline.cmdlen = 0;
ccline.cmdbufflen = 1;
ccline.cmdpos = 0;
cmdwin_result = Ctrl_C;
}
else
{
ccline.cmdlen = (int)STRLEN(ccline.cmdbuff);

View File

@@ -1267,6 +1267,13 @@
# undef FEAT_JOB_CHANNEL
#endif
/*
* +terminal ":terminal" command. Runs a terminal in a window.
*/
#if !defined(FEAT_JOB_CHANNEL) && defined(FEAT_TERMINAL)
# undef FEAT_TERMINAL
#endif
/*
* +signs Allow signs to be displayed to the left of text lines.
* Adds the ":sign" command.

View File

@@ -3166,6 +3166,7 @@ buf_write(
int device = FALSE; /* writing to a device */
stat_T st_old;
int prev_got_int = got_int;
int checking_conversion;
int file_readonly = FALSE; /* overwritten file is read-only */
static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
#if defined(UNIX) /*XXX fix me sometime? */
@@ -4343,13 +4344,41 @@ buf_write(
}
#endif
/*
* If conversion is taking place, we may first pretend to write and check
* for conversion errors. Then loop again to write for real.
* When not doing conversion this writes for real right away.
*/
for (checking_conversion = TRUE; ; checking_conversion = FALSE)
{
/*
* There is no need to check conversion when:
* - there is no conversion
* - we make a backup file, that can be restored in case of conversion
* failure.
*/
#ifdef FEAT_MBYTE
if (!converted || dobackup)
#endif
checking_conversion = FALSE;
if (checking_conversion)
{
/* Make sure we don't write anything. */
fd = -1;
write_info.bw_fd = fd;
}
else
{
/*
* Open the file "wfname" for writing.
* We may try to open the file twice: If we can't write to the
* file and forceit is TRUE we delete the existing file and try to create
* a new one. If this still fails we may have lost the original file!
* (this may happen when the user reached his quotum for number of files).
* Appending will fail if the file does not exist and forceit is FALSE.
* We may try to open the file twice: If we can't write to the file
* and forceit is TRUE we delete the existing file and try to
* create a new one. If this still fails we may have lost the
* original file! (this may happen when the user reached his
* quotum for number of files).
* Appending will fail if the file does not exist and forceit is
* FALSE.
*/
while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
@@ -4357,16 +4386,17 @@ buf_write(
, perm < 0 ? 0666 : (perm & 0777))) < 0)
{
/*
* A forced write will try to create a new file if the old one is
* still readonly. This may also happen when the directory is
* read-only. In that case the mch_remove() will fail.
* A forced write will try to create a new file if the old one
* is still readonly. This may also happen when the directory
* is read-only. In that case the mch_remove() will fail.
*/
if (errmsg == NULL)
{
#ifdef UNIX
stat_T st;
/* Don't delete the file when it's a hard or symbolic link. */
/* Don't delete the file when it's a hard or symbolic link.
*/
if ((!newfile && st_old.st_nlink > 1)
|| (mch_lstat((char *)fname, &st) == 0
&& (st.st_dev != st_old.st_dev
@@ -4385,7 +4415,8 @@ buf_write(
if (!(perm & 0200))
made_writable = TRUE;
perm |= 0200;
if (st_old.st_uid != getuid() || st_old.st_gid != getgid())
if (st_old.st_uid != getuid()
|| st_old.st_gid != getgid())
perm &= 0777;
#endif
if (!append) /* don't remove when appending */
@@ -4400,24 +4431,26 @@ restore_backup:
stat_T st;
/*
* If we failed to open the file, we don't need a backup. Throw it
* away. If we moved or removed the original file try to put the
* backup in its place.
* If we failed to open the file, we don't need a backup.
* Throw it away. If we moved or removed the original file
* try to put the backup in its place.
*/
if (backup != NULL && wfname == fname)
{
if (backup_copy)
{
/*
* There is a small chance that we removed the original,
* try to move the copy in its place.
* There is a small chance that we removed the
* original, try to move the copy in its place.
* This may not work if the vim_rename() fails.
* In that case we leave the copy around.
*/
/* If file does not exist, put the copy in its place */
/* If file does not exist, put the copy in its
* place */
if (mch_stat((char *)fname, &st) < 0)
vim_rename(backup, fname);
/* if original file does exist throw away the copy */
/* if original file does exist throw away the copy
*/
if (mch_stat((char *)fname, &st) >= 0)
mch_remove(backup);
}
@@ -4428,7 +4461,8 @@ restore_backup:
}
}
/* if original file no longer exists give an extra warning */
/* if original file no longer exists give an extra warning
*/
if (!newfile && mch_stat((char *)fname, &st) < 0)
end = 0;
}
@@ -4439,7 +4473,7 @@ restore_backup:
#endif
goto fail;
}
errmsg = NULL;
write_info.bw_fd = fd;
#if defined(MACOS_CLASSIC) || defined(WIN3264)
/* TODO: Is it need for MACOS_X? (Dany) */
@@ -4464,15 +4498,14 @@ restore_backup:
}
#endif
write_info.bw_fd = fd;
#ifdef FEAT_CRYPT
if (*buf->b_p_key != NUL && !filtering)
{
char_u *header;
int header_len;
buf->b_cryptstate = crypt_create_for_writing(crypt_get_method_nr(buf),
buf->b_cryptstate = crypt_create_for_writing(
crypt_get_method_nr(buf),
buf->b_p_key, &header, &header_len);
if (buf->b_cryptstate == NULL || header == NULL)
end = 0;
@@ -4490,6 +4523,8 @@ restore_backup:
}
}
#endif
}
errmsg = NULL;
write_info.bw_buf = buffer;
nchars = 0;
@@ -4503,8 +4538,8 @@ restore_backup:
#ifdef FEAT_MBYTE
/*
* The BOM is written just after the encryption magic number.
* Skip it when appending and the file already existed, the BOM only makes
* sense at the start of the file.
* Skip it when appending and the file already existed, the BOM only
* makes sense at the start of the file.
*/
if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
{
@@ -4523,8 +4558,12 @@ restore_backup:
#endif
#ifdef FEAT_PERSISTENT_UNDO
write_undo_file = (buf->b_p_udf && overwriting && !append
&& !filtering && reset_changed);
write_undo_file = (buf->b_p_udf
&& overwriting
&& !append
&& !filtering
&& reset_changed
&& !checking_conversion);
if (write_undo_file)
/* Prepare for computing the hash value of the text. */
sha256_start(&sha_ctx);
@@ -4546,7 +4585,8 @@ restore_backup:
ptr = ml_get_buf(buf, lnum, FALSE) - 1;
#ifdef FEAT_PERSISTENT_UNDO
if (write_undo_file)
sha256_update(&sha_ctx, ptr + 1, (UINT32_T)(STRLEN(ptr + 1) + 1));
sha256_update(&sha_ctx, ptr + 1,
(UINT32_T)(STRLEN(ptr + 1) + 1));
#endif
while ((c = *++ptr) != NUL)
{
@@ -4576,7 +4616,8 @@ restore_backup:
|| (lnum == end
&& (write_bin || !buf->b_p_fixeol)
&& (lnum == buf->b_no_eol_lnum
|| (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol))))
|| (lnum == buf->b_ml.ml_line_count
&& !buf->b_p_eol))))
{
++lnum; /* written the line, count it */
no_eol = TRUE;
@@ -4623,12 +4664,12 @@ restore_backup:
}
#ifdef VMS
/*
* On VMS there is a problem: newlines get added when writing blocks
* at a time. Fix it by writing a line at a time.
* On VMS there is a problem: newlines get added when writing
* blocks at a time. Fix it by writing a line at a time.
* This is much slower!
* Explanation: VAX/DECC RTL insists that records in some RMS
* structures end with a newline (carriage return) character, and if
* they don't it adds one.
* structures end with a newline (carriage return) character, and
* if they don't it adds one.
* With other RMS structures it works perfect without this fix.
*/
if (buf->b_fab_rfm == FAB$C_VFC
@@ -4666,15 +4707,29 @@ restore_backup:
nchars += len;
}
/* Stop when writing done or an error was encountered. */
if (!checking_conversion || end == 0)
break;
/* If no error happened until now, writing should be ok, so loop to
* really write the buffer. */
}
/* If we started writing, finish writing. Also when an error was
* encountered. */
if (!checking_conversion)
{
#if defined(UNIX) && defined(HAVE_FSYNC)
/* On many journalling file systems there is a bug that causes both the
* original and the backup file to be lost when halting the system right
* after writing the file. That's because only the meta-data is
* journalled. Syncing the file slows down the system, but assures it has
* been written to disk and we don't lose it.
* For a device do try the fsync() but don't complain if it does not work
* (could be a pipe).
* If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. */
/*
* On many journalling file systems there is a bug that causes both the
* original and the backup file to be lost when halting the system
* right after writing the file. That's because only the meta-data is
* journalled. Syncing the file slows down the system, but assures it
* has been written to disk and we don't lose it.
* For a device do try the fsync() but don't complain if it does not
* work (could be a pipe).
* If the 'fsync' option is FALSE, don't fsync(). Useful for laptops.
*/
if (p_fs && fsync(fd) != 0 && !device)
{
errmsg = (char_u *)_("E667: Fsync failed");
@@ -4689,8 +4744,8 @@ restore_backup:
#endif
#ifdef UNIX
/* When creating a new file, set its owner/group to that of the original
* file. Get the new device and inode number. */
/* When creating a new file, set its owner/group to that of the
* original file. Get the new device and inode number. */
if (backup != NULL && !backup_copy)
{
# ifdef HAVE_FCHOWN
@@ -4731,9 +4786,9 @@ restore_backup:
* Probably need to set the ACL before changing the user (can't set the
* ACL on a file the user doesn't own).
* On Solaris, with ZFS and the aclmode property set to "discard" (the
* default), chmod() discards all part of a file's ACL that don't represent
* the mode of the file. It's non-trivial for us to discover whether we're
* in that situation, so we simply always re-set the ACL.
* default), chmod() discards all part of a file's ACL that don't
* represent the mode of the file. It's non-trivial for us to discover
* whether we're in that situation, so we simply always re-set the ACL.
*/
# ifndef HAVE_SOLARIS_ZFS_ACL
if (!backup_copy)
@@ -4752,13 +4807,13 @@ restore_backup:
if (wfname != fname)
{
/*
* The file was written to a temp file, now it needs to be converted
* with 'charconvert' to (overwrite) the output file.
* The file was written to a temp file, now it needs to be
* converted with 'charconvert' to (overwrite) the output file.
*/
if (end != 0)
{
if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc,
wfname, fname) == FAIL)
if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc,
fenc, wfname, fname) == FAIL)
{
write_info.bw_conv_error = TRUE;
end = 0;
@@ -4768,9 +4823,13 @@ restore_backup:
vim_free(wfname);
}
#endif
}
if (end == 0)
{
/*
* Error encountered.
*/
if (errmsg == NULL)
{
#ifdef FEAT_MBYTE
@@ -5690,6 +5749,10 @@ buf_write_bytes(struct bw_info *ip)
}
#endif /* FEAT_MBYTE */
if (ip->bw_fd < 0)
/* Only checking conversion, which is OK if we get here. */
return OK;
#ifdef FEAT_CRYPT
if (flags & FIO_ENCRYPTED)
{
@@ -8800,7 +8863,7 @@ do_doautocmd(
/*
* Loop over the events.
*/
while (*arg && !VIM_ISWHITE(*arg))
while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg))
if (apply_autocmds_group(event_name2nr(arg, &arg),
fname, NULL, TRUE, group, curbuf, NULL))
nothing_done = FALSE;
@@ -9322,7 +9385,8 @@ apply_autocmds_group(
* Quickly return if there are no autocommands for this event or
* autocommands are blocked.
*/
if (first_autopat[(int)event] == NULL || autocmd_blocked > 0)
if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
|| autocmd_blocked > 0)
goto BYPASS_AU;
/*
@@ -9395,7 +9459,7 @@ apply_autocmds_group(
{
if (event == EVENT_COLORSCHEME || event == EVENT_OPTIONSET)
autocmd_fname = NULL;
else if (fname != NULL && *fname != NUL)
else if (fname != NULL && !ends_excmd(*fname))
autocmd_fname = fname;
else if (buf != NULL)
autocmd_fname = buf->b_ffname;

View File

@@ -467,6 +467,11 @@ flush_buffers(int flush_typeahead)
;
typebuf.tb_off = MAXMAPLEN;
typebuf.tb_len = 0;
#if defined(FEAT_CLIENTSERVER) || defined(FEAT_EVAL)
/* Reset the flag that text received from a client or from feedkeys()
* was inserted in the typeahead buffer. */
typebuf_was_filled = FALSE;
#endif
}
else /* remove mapped characters at the start only */
{

View File

@@ -1036,7 +1036,6 @@ EXTERN int skip_redraw INIT(= FALSE); /* skip redraw once */
EXTERN int do_redraw INIT(= FALSE); /* extra redraw once */
EXTERN int need_highlight_changed INIT(= TRUE);
EXTERN char_u *use_viminfo INIT(= NULL); /* name of viminfo file to use */
#define NSCRIPT 15
EXTERN FILE *scriptin[NSCRIPT]; /* streams to read script from */
@@ -1659,6 +1658,7 @@ EXTERN int in_free_unref_items INIT(= FALSE);
#ifdef FEAT_TIMERS
EXTERN int did_add_timer INIT(= FALSE);
EXTERN int timer_busy INIT(= 0); /* when timer is inside vgetc() then > 0 */
#endif
#ifdef FEAT_EVAL

View File

@@ -779,6 +779,7 @@ get_exceptions(void)
static int initialised = 0;
#define PYINITIALISED initialised
static int python_end_called = FALSE;
#define DESTRUCTOR_FINISH(self) self->ob_type->tp_free((PyObject*)self);
@@ -878,6 +879,7 @@ python_end(void)
if (recurse != 0)
return;
python_end_called = TRUE;
++recurse;
#ifdef DYNAMIC_PYTHON
@@ -1040,6 +1042,8 @@ DoPyCommand(const char *cmd, rangeinitializer init_range, runner run, void *arg)
}
++recursive;
#endif
if (python_end_called)
return;
#if defined(MACOS) && !defined(MACOS_X_UNIX)
GetPort(&oldPort);
@@ -1568,7 +1572,7 @@ do_pyeval (char_u *str, typval_T *rettv)
(rangeinitializer) init_range_eval,
(runner) run_eval,
(void *) rettv);
switch(rettv->v_type)
switch (rettv->v_type)
{
case VAR_DICT: ++rettv->vval.v_dict->dv_refcount; break;
case VAR_LIST: ++rettv->vval.v_list->lv_refcount; break;

View File

@@ -733,8 +733,8 @@ get_py3_exceptions(void)
#endif /* DYNAMIC_PYTHON3 */
static int py3initialised = 0;
#define PYINITIALISED py3initialised
static int python_end_called = FALSE;
#define DESTRUCTOR_FINISH(self) Py_TYPE(self)->tp_free((PyObject*)self)
@@ -817,6 +817,7 @@ python3_end(void)
if (recurse != 0)
return;
python_end_called = TRUE;
++recurse;
#ifdef DYNAMIC_PYTHON3
@@ -938,6 +939,9 @@ DoPyCommand(const char *cmd, rangeinitializer init_range, runner run, void *arg)
PyObject *cmdbytes;
PyGILState_STATE pygilstate;
if (python_end_called)
goto theend;
#if defined(MACOS) && !defined(MACOS_X_UNIX)
GetPort(&oldPort);
/* Check if the Python library is available */

View File

@@ -112,6 +112,7 @@
/* Used for the sgr mouse. */
#define KS_SGR_MOUSE 237
#define KS_SGR_MOUSE_RELEASE 236
/*
* Filler used after KS_SPECIAL and others
@@ -139,6 +140,8 @@
/*
* Codes for keys that do not have a termcap name.
* The numbers are fixed to make sure that recorded key sequences remain valid.
* Add new entries at the end, not halfway.
*
* K_SPECIAL KS_EXTRA KE_xxx
*/
@@ -146,125 +149,126 @@ enum key_extra
{
KE_NAME = 3 /* name of this terminal entry */
, KE_S_UP /* shift-up */
, KE_S_DOWN /* shift-down */
, KE_S_UP = 4 /* shift-up */
, KE_S_DOWN = 5 /* shift-down */
, KE_S_F1 /* shifted function keys */
, KE_S_F2
, KE_S_F3
, KE_S_F4
, KE_S_F5
, KE_S_F6
, KE_S_F7
, KE_S_F8
, KE_S_F9
, KE_S_F10
, KE_S_F1 = 6 /* shifted function keys */
, KE_S_F2 = 7
, KE_S_F3 = 8
, KE_S_F4 = 9
, KE_S_F5 = 10
, KE_S_F6 = 11
, KE_S_F7 = 12
, KE_S_F8 = 13
, KE_S_F9 = 14
, KE_S_F10 = 15
, KE_S_F11
, KE_S_F12
, KE_S_F13
, KE_S_F14
, KE_S_F15
, KE_S_F16
, KE_S_F17
, KE_S_F18
, KE_S_F19
, KE_S_F20
, KE_S_F11 = 16
, KE_S_F12 = 17
, KE_S_F13 = 18
, KE_S_F14 = 19
, KE_S_F15 = 20
, KE_S_F16 = 21
, KE_S_F17 = 22
, KE_S_F18 = 23
, KE_S_F19 = 24
, KE_S_F20 = 25
, KE_S_F21
, KE_S_F22
, KE_S_F23
, KE_S_F24
, KE_S_F25
, KE_S_F26
, KE_S_F27
, KE_S_F28
, KE_S_F29
, KE_S_F30
, KE_S_F21 = 26
, KE_S_F22 = 27
, KE_S_F23 = 28
, KE_S_F24 = 29
, KE_S_F25 = 30
, KE_S_F26 = 31
, KE_S_F27 = 32
, KE_S_F28 = 33
, KE_S_F29 = 34
, KE_S_F30 = 35
, KE_S_F31
, KE_S_F32
, KE_S_F33
, KE_S_F34
, KE_S_F35
, KE_S_F36
, KE_S_F37
, KE_S_F31 = 36
, KE_S_F32 = 37
, KE_S_F33 = 38
, KE_S_F34 = 39
, KE_S_F35 = 40
, KE_S_F36 = 41
, KE_S_F37 = 42
, KE_MOUSE /* mouse event start */
, KE_MOUSE = 43 /* mouse event start */
/*
* Symbols for pseudo keys which are translated from the real key symbols
* above.
*/
, KE_LEFTMOUSE /* Left mouse button click */
, KE_LEFTDRAG /* Drag with left mouse button down */
, KE_LEFTRELEASE /* Left mouse button release */
, KE_MIDDLEMOUSE /* Middle mouse button click */
, KE_MIDDLEDRAG /* Drag with middle mouse button down */
, KE_MIDDLERELEASE /* Middle mouse button release */
, KE_RIGHTMOUSE /* Right mouse button click */
, KE_RIGHTDRAG /* Drag with right mouse button down */
, KE_RIGHTRELEASE /* Right mouse button release */
, KE_LEFTMOUSE = 44 /* Left mouse button click */
, KE_LEFTDRAG = 45 /* Drag with left mouse button down */
, KE_LEFTRELEASE = 46 /* Left mouse button release */
, KE_MIDDLEMOUSE = 47 /* Middle mouse button click */
, KE_MIDDLEDRAG = 48 /* Drag with middle mouse button down */
, KE_MIDDLERELEASE = 49 /* Middle mouse button release */
, KE_RIGHTMOUSE = 50 /* Right mouse button click */
, KE_RIGHTDRAG = 51 /* Drag with right mouse button down */
, KE_RIGHTRELEASE = 52 /* Right mouse button release */
, KE_IGNORE /* Ignored mouse drag/release */
, KE_IGNORE = 53 /* Ignored mouse drag/release */
, KE_TAB /* unshifted TAB key */
, KE_S_TAB_OLD /* shifted TAB key (no longer used) */
, KE_TAB = 54 /* unshifted TAB key */
, KE_S_TAB_OLD = 55 /* shifted TAB key (no longer used) */
, KE_XF1 /* extra vt100 function keys for xterm */
, KE_XF2
, KE_XF3
, KE_XF4
, KE_XEND /* extra (vt100) end key for xterm */
, KE_ZEND /* extra (vt100) end key for xterm */
, KE_XHOME /* extra (vt100) home key for xterm */
, KE_ZHOME /* extra (vt100) home key for xterm */
, KE_XUP /* extra vt100 cursor keys for xterm */
, KE_XDOWN
, KE_XLEFT
, KE_XRIGHT
, KE_SNIFF_UNUSED = 56 /* obsolete */
, KE_XF1 = 57 /* extra vt100 function keys for xterm */
, KE_XF2 = 58
, KE_XF3 = 59
, KE_XF4 = 60
, KE_XEND = 61 /* extra (vt100) end key for xterm */
, KE_ZEND = 62 /* extra (vt100) end key for xterm */
, KE_XHOME = 63 /* extra (vt100) home key for xterm */
, KE_ZHOME = 64 /* extra (vt100) home key for xterm */
, KE_XUP = 65 /* extra vt100 cursor keys for xterm */
, KE_XDOWN = 66
, KE_XLEFT = 67
, KE_XRIGHT = 68
, KE_LEFTMOUSE_NM /* non-mappable Left mouse button click */
, KE_LEFTRELEASE_NM /* non-mappable left mouse button release */
, KE_LEFTMOUSE_NM = 69 /* non-mappable Left mouse button click */
, KE_LEFTRELEASE_NM = 70 /* non-mappable left mouse button release */
, KE_S_XF1 /* extra vt100 shifted function keys for xterm */
, KE_S_XF2
, KE_S_XF3
, KE_S_XF4
, KE_S_XF1 = 71 /* vt100 shifted function keys for xterm */
, KE_S_XF2 = 72
, KE_S_XF3 = 73
, KE_S_XF4 = 74
/* NOTE: The scroll wheel events are inverted: i.e. UP is the same as
* moving the actual scroll wheel down, LEFT is the same as moving the
* scroll wheel right. */
, KE_MOUSEDOWN /* scroll wheel pseudo-button Down */
, KE_MOUSEUP /* scroll wheel pseudo-button Up */
, KE_MOUSELEFT /* scroll wheel pseudo-button Left */
, KE_MOUSERIGHT /* scroll wheel pseudo-button Right */
, KE_MOUSEDOWN = 75 /* scroll wheel pseudo-button Down */
, KE_MOUSEUP = 76 /* scroll wheel pseudo-button Up */
, KE_MOUSELEFT = 77 /* scroll wheel pseudo-button Left */
, KE_MOUSERIGHT = 78 /* scroll wheel pseudo-button Right */
, KE_KINS /* keypad Insert key */
, KE_KDEL /* keypad Delete key */
, KE_KINS = 79 /* keypad Insert key */
, KE_KDEL = 80 /* keypad Delete key */
, KE_CSI /* CSI typed directly */
, KE_SNR /* <SNR> */
, KE_PLUG /* <Plug> */
, KE_CMDWIN /* open command-line window from Command-line Mode */
, KE_CSI = 81 /* CSI typed directly */
, KE_SNR = 82 /* <SNR> */
, KE_PLUG = 83 /* <Plug> */
, KE_CMDWIN = 84 /* open command-line window from Command-line Mode */
, KE_C_LEFT /* control-left */
, KE_C_RIGHT /* control-right */
, KE_C_HOME /* control-home */
, KE_C_END /* control-end */
, KE_C_LEFT = 85 /* control-left */
, KE_C_RIGHT = 86 /* control-right */
, KE_C_HOME = 87 /* control-home */
, KE_C_END = 88 /* control-end */
, KE_X1MOUSE /* X1/X2 mouse-buttons */
, KE_X1DRAG
, KE_X1RELEASE
, KE_X2MOUSE
, KE_X2DRAG
, KE_X2RELEASE
, KE_X1MOUSE = 89 /* X1/X2 mouse-buttons */
, KE_X1DRAG = 90
, KE_X1RELEASE = 91
, KE_X2MOUSE = 92
, KE_X2DRAG = 93
, KE_X2RELEASE = 94
, KE_DROP /* DnD data is available */
, KE_CURSORHOLD /* CursorHold event */
, KE_NOP /* doesn't do something */
, KE_FOCUSGAINED /* focus gained */
, KE_FOCUSLOST /* focus lost */
, KE_DROP = 95 /* DnD data is available */
, KE_CURSORHOLD = 96 /* CursorHold event */
, KE_NOP = 97 /* doesn't do something */
, KE_FOCUSGAINED = 98 /* focus gained */
, KE_FOCUSLOST = 99 /* focus lost */
};
/*
@@ -416,6 +420,7 @@ enum key_extra
#define K_PTERM_MOUSE TERMCAP2KEY(KS_PTERM_MOUSE, KE_FILLER)
#define K_URXVT_MOUSE TERMCAP2KEY(KS_URXVT_MOUSE, KE_FILLER)
#define K_SGR_MOUSE TERMCAP2KEY(KS_SGR_MOUSE, KE_FILLER)
#define K_SGR_MOUSERELEASE TERMCAP2KEY(KS_SGR_MOUSE_RELEASE, KE_FILLER)
#define K_SELECT TERMCAP2KEY(KS_SELECT, KE_FILLER)
#define K_TEAROFF TERMCAP2KEY(KS_TEAROFF, KE_FILLER)

13
src/libvterm/.bzrignore Normal file
View File

@@ -0,0 +1,13 @@
.libs
*.lo
*.la
bin/*
!bin/*.c
pangoterm
t/test
t/suites.h
t/externs.h
t/harness
src/encoding/*.inc

17
src/libvterm/.gitignore vendored Normal file
View File

@@ -0,0 +1,17 @@
*~
*.swp
tags
src/*.o
src/*.lo
libvterm.la
bin/unterm
bin/vterm-ctrl
bin/vterm-dump
t/harness
t/harness.lo
t/harness.o
.libs/

23
src/libvterm/LICENSE Normal file
View File

@@ -0,0 +1,23 @@
The MIT License
Copyright (c) 2008 Paul Evans <leonerd@leonerd.org.uk>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

145
src/libvterm/Makefile Normal file
View File

@@ -0,0 +1,145 @@
ifeq ($(shell uname),Darwin)
LIBTOOL ?= glibtool
else
LIBTOOL ?= libtool
endif
ifneq ($(VERBOSE),1)
LIBTOOL +=--quiet
endif
# override CFLAGS +=-Wall -Iinclude -std=c99 -DINLINE="static inline" -DUSE_INLINE
override CFLAGS +=-Wall -Iinclude -std=c90 -Wpedantic -DINLINE=""
ifeq ($(shell uname),SunOS)
override CFLAGS +=-D__EXTENSIONS__ -D_XPG6 -D__XOPEN_OR_POSIX
endif
ifeq ($(DEBUG),1)
override CFLAGS +=-ggdb -DDEBUG
endif
ifeq ($(PROFILE),1)
override CFLAGS +=-pg
override LDFLAGS+=-pg
endif
CFILES=$(sort $(wildcard src/*.c))
HFILES=$(sort $(wildcard include/*.h))
OBJECTS=$(CFILES:.c=.lo)
LIBRARY=libvterm.la
BINFILES_SRC=$(sort $(wildcard bin/*.c))
BINFILES=$(BINFILES_SRC:.c=)
TBLFILES=$(sort $(wildcard src/encoding/*.tbl))
INCFILES=$(TBLFILES:.tbl=.inc)
HFILES_INT=$(sort $(wildcard src/*.h)) $(HFILES)
VERSION_MAJOR=0
VERSION_MINOR=0
VERSION_CURRENT=0
VERSION_REVISION=0
VERSION_AGE=0
VERSION=0
PREFIX=/usr/local
BINDIR=$(PREFIX)/bin
LIBDIR=$(PREFIX)/lib
INCDIR=$(PREFIX)/include
MANDIR=$(PREFIX)/share/man
MAN3DIR=$(MANDIR)/man3
all: $(LIBRARY) $(BINFILES)
$(LIBRARY): $(OBJECTS)
@echo LINK $@
@$(LIBTOOL) --mode=link --tag=CC $(CC) -rpath $(LIBDIR) -version-info $(VERSION_CURRENT):$(VERSION_REVISION):$(VERSION_AGE) -o $@ $^ $(LDFLAGS)
src/%.lo: src/%.c $(HFILES_INT)
@echo CC $<
@$(LIBTOOL) --mode=compile --tag=CC $(CC) $(CFLAGS) -o $@ -c $<
src/encoding/%.inc: src/encoding/%.tbl
@echo TBL $<
@perl -CSD tbl2inc_c.pl $< >$@
src/encoding.lo: $(INCFILES)
bin/%: bin/%.c $(LIBRARY)
@echo CC $<
@$(LIBTOOL) --mode=link --tag=CC $(CC) $(CFLAGS) -o $@ $< -lvterm $(LDFLAGS)
t/harness.lo: t/harness.c $(HFILES)
@echo CC $<
@$(LIBTOOL) --mode=compile --tag=CC $(CC) $(CFLAGS) -o $@ -c $<
t/harness: t/harness.lo $(LIBRARY)
@echo LINK $@
@$(LIBTOOL) --mode=link --tag=CC $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
.PHONY: test
test: $(LIBRARY) t/harness
for T in `ls t/[0-9]*.test`; do echo "** $$T **"; perl t/run-test.pl $$T $(if $(VALGRIND),--valgrind) || exit 1; done
.PHONY: clean
clean:
$(LIBTOOL) --mode=clean rm -f $(OBJECTS) $(INCFILES)
$(LIBTOOL) --mode=clean rm -f t/harness.lo t/harness
$(LIBTOOL) --mode=clean rm -f $(LIBRARY) $(BINFILES)
.PHONY: install
install: install-inc install-lib install-bin
install-inc:
install -d $(DESTDIR)$(INCDIR)
install -m644 $(HFILES) $(DESTDIR)$(INCDIR)
install -d $(DESTDIR)$(LIBDIR)/pkgconfig
sed -e "s,@PREFIX@,$(PREFIX)," -e "s,@LIBDIR@,$(LIBDIR)," -e "s,@VERSION@,$(VERSION)," <vterm.pc.in >$(DESTDIR)$(LIBDIR)/pkgconfig/vterm.pc
install-lib: $(LIBRARY)
install -d $(DESTDIR)$(LIBDIR)
$(LIBTOOL) --mode=install install $(LIBRARY) $(DESTDIR)$(LIBDIR)/$(LIBRARY)
$(LIBTOOL) --mode=finish $(DESTDIR)$(LIBDIR)
install-bin: $(BINFILES)
install -d $(DESTDIR)$(BINDIR)
$(LIBTOOL) --mode=install install $(BINFILES) $(DESTDIR)$(BINDIR)/
# DIST CUT
VERSION=$(VERSION_MAJOR).$(VERSION_MINOR)
DISTDIR=libvterm-$(VERSION)
distdir: $(INCFILES)
mkdir __distdir
cp LICENSE __distdir
mkdir __distdir/src
cp src/*.c src/*.h __distdir/src
mkdir __distdir/src/encoding
cp src/encoding/*.inc __distdir/src/encoding
mkdir __distdir/include
cp include/*.h __distdir/include
mkdir __distdir/bin
cp bin/*.c __distdir/bin
mkdir __distdir/t
cp t/*.test t/harness.c t/run-test.pl __distdir/t
sed "s,@VERSION@,$(VERSION)," <vterm.pc.in >__distdir/vterm.pc.in
sed "/^# DIST CUT/Q" <Makefile >__distdir/Makefile
mv __distdir $(DISTDIR)
TARBALL=$(DISTDIR).tar.gz
dist: distdir
tar -czf $(TARBALL) $(DISTDIR)
rm -rf $(DISTDIR)
dist+bzr:
$(MAKE) dist VERSION=$(VERSION)+bzr`bzr revno`
distdir+bzr:
$(MAKE) distdir VERSION=$(VERSION)+bzr`bzr revno`

13
src/libvterm/README Normal file
View File

@@ -0,0 +1,13 @@
This is a MODIFIED version of libvterm.
The original can be found:
On the original site (tar archive and Bazaar repository):
http://www.leonerd.org.uk/code/libvterm/
Cloned on Github:
https://github.com/neovim/libvterm
Modifications:
- Add a .gitignore file.
- Convert from C99 to C90.
- Other changes to support embedding in Vim.
-

287
src/libvterm/bin/unterm.c Normal file
View File

@@ -0,0 +1,287 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <unistd.h>
#include "vterm.h"
#define DEFINE_INLINES
#include "../src/utf8.h" /* fill_utf8 */
#define streq(a,b) (!strcmp(a,b))
static VTerm *vt;
static VTermScreen *vts;
static int cols;
static int rows;
static enum {
FORMAT_PLAIN,
FORMAT_SGR
} format = FORMAT_PLAIN;
static int col2index(VTermColor target)
{
int index;
for(index = 0; index < 256; index++) {
VTermColor col;
vterm_state_get_palette_color(NULL, index, &col);
if(col.red == target.red && col.green == target.green && col.blue == target.blue)
return index;
}
return -1;
}
static void dump_cell(const VTermScreenCell *cell, const VTermScreenCell *prevcell)
{
switch(format) {
case FORMAT_PLAIN:
break;
case FORMAT_SGR:
{
/* If all 7 attributes change, that means 7 SGRs max */
/* Each colour could consume up to 3 */
int sgr[7 + 2*3]; int sgri = 0;
if(!prevcell->attrs.bold && cell->attrs.bold)
sgr[sgri++] = 1;
if(prevcell->attrs.bold && !cell->attrs.bold)
sgr[sgri++] = 22;
if(!prevcell->attrs.underline && cell->attrs.underline)
sgr[sgri++] = 4;
if(prevcell->attrs.underline && !cell->attrs.underline)
sgr[sgri++] = 24;
if(!prevcell->attrs.italic && cell->attrs.italic)
sgr[sgri++] = 3;
if(prevcell->attrs.italic && !cell->attrs.italic)
sgr[sgri++] = 23;
if(!prevcell->attrs.blink && cell->attrs.blink)
sgr[sgri++] = 5;
if(prevcell->attrs.blink && !cell->attrs.blink)
sgr[sgri++] = 25;
if(!prevcell->attrs.reverse && cell->attrs.reverse)
sgr[sgri++] = 7;
if(prevcell->attrs.reverse && !cell->attrs.reverse)
sgr[sgri++] = 27;
if(!prevcell->attrs.strike && cell->attrs.strike)
sgr[sgri++] = 9;
if(prevcell->attrs.strike && !cell->attrs.strike)
sgr[sgri++] = 29;
if(!prevcell->attrs.font && cell->attrs.font)
sgr[sgri++] = 10 + cell->attrs.font;
if(prevcell->attrs.font && !cell->attrs.font)
sgr[sgri++] = 10;
if(prevcell->fg.red != cell->fg.red ||
prevcell->fg.green != cell->fg.green ||
prevcell->fg.blue != cell->fg.blue) {
int index = col2index(cell->fg);
if(index == -1)
sgr[sgri++] = 39;
else if(index < 8)
sgr[sgri++] = 30 + index;
else if(index < 16)
sgr[sgri++] = 90 + (index - 8);
else {
sgr[sgri++] = 38;
sgr[sgri++] = 5 | (1<<31);
sgr[sgri++] = index | (1<<31);
}
}
if(prevcell->bg.red != cell->bg.red ||
prevcell->bg.green != cell->bg.green ||
prevcell->bg.blue != cell->bg.blue) {
int index = col2index(cell->bg);
if(index == -1)
sgr[sgri++] = 49;
else if(index < 8)
sgr[sgri++] = 40 + index;
else if(index < 16)
sgr[sgri++] = 100 + (index - 8);
else {
sgr[sgri++] = 48;
sgr[sgri++] = 5 | (1<<31);
sgr[sgri++] = index | (1<<31);
}
}
if(!sgri)
break;
printf("\x1b[");
{
int i;
for(i = 0; i < sgri; i++)
printf(!i ? "%d" :
sgr[i] & (1<<31) ? ":%d" :
";%d",
sgr[i] & ~(1<<31));
}
printf("m");
}
break;
}
{
int i;
for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) {
char bytes[6];
bytes[fill_utf8(cell->chars[i], bytes)] = 0;
printf("%s", bytes);
}
}
}
static void dump_eol(const VTermScreenCell *prevcell)
{
switch(format) {
case FORMAT_PLAIN:
break;
case FORMAT_SGR:
if(prevcell->attrs.bold || prevcell->attrs.underline || prevcell->attrs.italic ||
prevcell->attrs.blink || prevcell->attrs.reverse || prevcell->attrs.strike ||
prevcell->attrs.font)
printf("\x1b[m");
break;
}
printf("\n");
}
void dump_row(int row)
{
VTermPos pos;
VTermScreenCell prevcell;
pos.row = row;
pos.col = 0;
memset(&prevcell, 0, sizeof(prevcell));
vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg);
while(pos.col < cols) {
VTermScreenCell cell;
vterm_screen_get_cell(vts, pos, &cell);
dump_cell(&cell, &prevcell);
pos.col += cell.width;
prevcell = cell;
}
dump_eol(&prevcell);
}
static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
{
VTermScreenCell prevcell;
int col;
memset(&prevcell, 0, sizeof(prevcell));
vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg);
for(col = 0; col < cols; col++) {
dump_cell(cells + col, &prevcell);
prevcell = cells[col];
}
dump_eol(&prevcell);
return 1;
}
static int screen_resize(int new_rows, int new_cols, void *user)
{
rows = new_rows;
cols = new_cols;
return 1;
}
static VTermScreenCallbacks cb_screen = {
NULL, /* damage */
NULL, /* moverect */
NULL, /* movecursor */
NULL, /* settermprop */
NULL, /* bell */
&screen_resize, /* resize */
&screen_sb_pushline, /* sb_pushline */
NULL, /* popline */
};
int main(int argc, char *argv[])
{
int opt;
const char *file;
int fd;
int len;
char buffer[1024];
int row;
rows = 25;
cols = 80;
while((opt = getopt(argc, argv, "f:l:c:")) != -1) {
switch(opt) {
case 'f':
if(streq(optarg, "plain"))
format = FORMAT_PLAIN;
else if(streq(optarg, "sgr"))
format = FORMAT_SGR;
else {
fprintf(stderr, "Unrecognised format '%s'\n", optarg);
exit(1);
}
break;
case 'l':
rows = atoi(optarg);
if(!rows)
rows = 25;
break;
case 'c':
cols = atoi(optarg);
if(!cols)
cols = 80;
break;
}
}
file = argv[optind++];
fd = open(file, O_RDONLY);
if(fd == -1) {
fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno));
exit(1);
}
vt = vterm_new(rows, cols);
vterm_set_utf8(vt, true);
vts = vterm_obtain_screen(vt);
vterm_screen_set_callbacks(vts, &cb_screen, NULL);
vterm_screen_reset(vts, 1);
while((len = read(fd, buffer, sizeof(buffer))) > 0) {
vterm_input_write(vt, buffer, len);
}
for(row = 0; row < rows; row++) {
dump_row(row);
}
close(fd);
vterm_free(vt);
return 0;
}

View File

@@ -0,0 +1,362 @@
#define _XOPEN_SOURCE 500 /* strdup */
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define streq(a,b) (strcmp(a,b)==0)
#include <termios.h>
static char *getvalue(int *argip, int argc, char *argv[])
{
if(*argip >= argc) {
fprintf(stderr, "Expected an option value\n");
exit(1);
}
return argv[(*argip)++];
}
static int getchoice(int *argip, int argc, char *argv[], const char *options[])
{
const char *arg = getvalue(argip, argc, argv);
int value = -1;
while(options[++value])
if(streq(arg, options[value]))
return value;
fprintf(stderr, "Unrecognised option value %s\n", arg);
exit(1);
}
typedef enum {
OFF,
ON,
QUERY
} BoolQuery;
static BoolQuery getboolq(int *argip, int argc, char *argv[])
{
const char *choices[] = {"off", "on", "query", NULL};
return getchoice(argip, argc, argv, choices);
}
static char *helptext[] = {
"reset",
"s8c1t [off|on]",
"keypad [app|num]",
"screen [off|on|query]",
"cursor [off|on|query]",
"curblink [off|on|query]",
"curshape [block|under|bar|query]",
"mouse [off|click|clickdrag|motion]",
"altscreen [off|on|query]",
"bracketpaste [off|on|query]",
"icontitle [STR]",
"icon [STR]",
"title [STR]",
NULL
};
static bool seticanon(bool icanon, bool echo)
{
struct termios termios;
tcgetattr(0, &termios);
bool ret = (termios.c_lflag & ICANON);
if(icanon) termios.c_lflag |= ICANON;
else termios.c_lflag &= ~ICANON;
if(echo) termios.c_lflag |= ECHO;
else termios.c_lflag &= ~ECHO;
tcsetattr(0, TCSANOW, &termios);
return ret;
}
static void await_c1(int c1)
{
int c;
/* await CSI - 8bit or 2byte 7bit form */
bool in_esc = false;
while((c = getchar())) {
if(c == c1)
break;
if(in_esc && c == (char)(c1 - 0x40))
break;
if(!in_esc && c == 0x1b)
in_esc = true;
else
in_esc = false;
}
}
static char *read_csi()
{
unsigned char csi[32];
int i = 0;
await_c1(0x9B); /* CSI */
/* TODO: This really should be a more robust CSI parser
*/
for(; i < sizeof(csi)-1; i++) {
int c = csi[i] = getchar();
if(c >= 0x40 && c <= 0x7e)
break;
}
csi[++i] = 0;
/* TODO: returns longer than 32? */
return strdup((char *)csi);
}
static char *read_dcs()
{
unsigned char dcs[32];
bool in_esc = false;
int i;
await_c1(0x90);
for(i = 0; i < sizeof(dcs)-1; ) {
char c = getchar();
if(c == 0x9c) /* ST */
break;
if(in_esc && c == 0x5c)
break;
if(!in_esc && c == 0x1b)
in_esc = true;
else {
dcs[i++] = c;
in_esc = false;
}
}
dcs[++i] = 0;
return strdup((char *)dcs);
}
static void usage(int exitcode)
{
char **p;
fprintf(stderr, "Control a libvterm-based terminal\n"
"\n"
"Options:\n");
for(p = helptext; *p; p++)
fprintf(stderr, " %s\n", *p);
exit(exitcode);
}
static bool query_dec_mode(int mode)
{
char *s = NULL;
printf("\x1b[?%d$p", mode);
do {
int reply_mode, reply_value;
char reply_cmd;
if(s)
free(s);
s = read_csi();
/* expect "?" mode ";" value "$y" */
/* If the sscanf format string ends in a literal, we can't tell from
* its return value if it matches. Hence we'll %c the cmd and check it
* explicitly
*/
if(sscanf(s, "?%d;%d$%c", &reply_mode, &reply_value, &reply_cmd) < 3)
continue;
if(reply_cmd != 'y')
continue;
if(reply_mode != mode)
continue;
free(s);
if(reply_value == 1 || reply_value == 3)
return true;
if(reply_value == 2 || reply_value == 4)
return false;
printf("Unrecognised reply to DECRQM: %d\n", reply_value);
return false;
} while(1);
}
static void do_dec_mode(int mode, BoolQuery val, const char *name)
{
switch(val) {
case OFF:
case ON:
printf("\x1b[?%d%c", mode, val == ON ? 'h' : 'l');
break;
case QUERY:
if(query_dec_mode(mode))
printf("%s on\n", name);
else
printf("%s off\n", name);
break;
}
}
static int query_rqss_numeric(char *cmd)
{
char *s = NULL;
printf("\x1bP$q%s\x1b\\", cmd);
do {
int num;
if(s)
free(s);
s = read_dcs();
if(!s)
return -1;
if(strlen(s) < strlen(cmd))
return -1;
if(strcmp(s + strlen(s) - strlen(cmd), cmd) != 0) {
printf("No match\n");
continue;
}
if(s[0] != '1' || s[1] != '$' || s[2] != 'r')
return -1;
if(sscanf(s + 3, "%d", &num) != 1)
return -1;
return num;
} while(1);
}
bool wasicanon;
void restoreicanon(void)
{
seticanon(wasicanon, true);
}
int main(int argc, char *argv[])
{
int argi = 1;
if(argc == 1)
usage(0);
wasicanon = seticanon(false, false);
atexit(restoreicanon);
while(argi < argc) {
const char *arg = argv[argi++];
if(streq(arg, "reset")) {
printf("\x1b" "c");
}
else if(streq(arg, "s8c1t")) {
const char *choices[] = {"off", "on", NULL};
switch(getchoice(&argi, argc, argv, choices)) {
case 0:
printf("\x1b F"); break;
case 1:
printf("\x1b G"); break;
}
}
else if(streq(arg, "keypad")) {
const char *choices[] = {"app", "num", NULL};
switch(getchoice(&argi, argc, argv, choices)) {
case 0:
printf("\x1b="); break;
case 1:
printf("\x1b>"); break;
}
}
else if(streq(arg, "screen")) {
do_dec_mode(5, getboolq(&argi, argc, argv), "screen");
}
else if(streq(arg, "cursor")) {
do_dec_mode(25, getboolq(&argi, argc, argv), "cursor");
}
else if(streq(arg, "curblink")) {
do_dec_mode(12, getboolq(&argi, argc, argv), "curblink");
}
else if(streq(arg, "curshape")) {
/* TODO: This ought to query the current value of DECSCUSR because it */
/* may need blinking on or off */
const char *choices[] = {"block", "under", "bar", "query", NULL};
int shape = getchoice(&argi, argc, argv, choices);
switch(shape) {
case 3: /* query */
shape = query_rqss_numeric(" q");
switch(shape) {
case 1: case 2:
printf("curshape block\n");
break;
case 3: case 4:
printf("curshape under\n");
break;
case 5: case 6:
printf("curshape bar\n");
break;
}
break;
case 0:
case 1:
case 2:
printf("\x1b[%d q", 1 + (shape * 2));
break;
}
}
else if(streq(arg, "mouse")) {
const char *choices[] = {"off", "click", "clickdrag", "motion", NULL};
switch(getchoice(&argi, argc, argv, choices)) {
case 0:
printf("\x1b[?1000l"); break;
case 1:
printf("\x1b[?1000h"); break;
case 2:
printf("\x1b[?1002h"); break;
case 3:
printf("\x1b[?1003h"); break;
}
}
else if(streq(arg, "altscreen")) {
do_dec_mode(1049, getboolq(&argi, argc, argv), "altscreen");
}
else if(streq(arg, "bracketpaste")) {
do_dec_mode(2004, getboolq(&argi, argc, argv), "bracketpaste");
}
else if(streq(arg, "icontitle")) {
printf("\x1b]0;%s\a", getvalue(&argi, argc, argv));
}
else if(streq(arg, "icon")) {
printf("\x1b]1;%s\a", getvalue(&argi, argc, argv));
}
else if(streq(arg, "title")) {
printf("\x1b]2;%s\a", getvalue(&argi, argc, argv));
}
else {
fprintf(stderr, "Unrecognised command %s\n", arg);
exit(1);
}
}
return 0;
}

View File

@@ -0,0 +1,231 @@
/* Require getopt(3) */
#define _XOPEN_SOURCE
#include <stdio.h>
#include <string.h>
#define streq(a,b) (strcmp(a,b)==0)
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "vterm.h"
static const char *special_begin = "{";
static const char *special_end = "}";
static int parser_text(const char bytes[], size_t len, void *user)
{
unsigned char *b = (unsigned char *)bytes;
int i;
for(i = 0; i < len; /* none */) {
if(b[i] < 0x20) /* C0 */
break;
else if(b[i] < 0x80) /* ASCII */
i++;
else if(b[i] < 0xa0) /* C1 */
break;
else if(b[i] < 0xc0) /* UTF-8 continuation */
break;
else if(b[i] < 0xe0) { /* UTF-8 2-byte */
/* 2-byte UTF-8 */
if(len < i+2) break;
i += 2;
}
else if(b[i] < 0xf0) { /* UTF-8 3-byte */
if(len < i+3) break;
i += 3;
}
else if(b[i] < 0xf8) { /* UTF-8 4-byte */
if(len < i+4) break;
i += 4;
}
else /* otherwise invalid */
break;
}
printf("%.*s", i, b);
return i;
}
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
static const char *name_c0[] = {
"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "LS0", "LS1",
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US",
};
static const char *name_c1[] = {
NULL, NULL, "BPH", "NBH", NULL, "NEL", "SSA", "ESA", "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
"DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA", "SOS", NULL, "SCI", "CSI", "ST", "OSC", "PM", "APC",
};
static int parser_control(unsigned char control, void *user)
{
if(control < 0x20)
printf("%s%s%s", special_begin, name_c0[control], special_end);
else if(control >= 0x80 && control < 0xa0 && name_c1[control - 0x80])
printf("%s%s%s", special_begin, name_c1[control - 0x80], special_end);
else
printf("%sCONTROL 0x%02x%s", special_begin, control, special_end);
if(control == 0x0a)
printf("\n");
return 1;
}
static int parser_escape(const char bytes[], size_t len, void *user)
{
if(bytes[0] >= 0x20 && bytes[0] < 0x30) {
if(len < 2)
return -1;
len = 2;
}
else {
len = 1;
}
printf("%sESC %.*s%s", special_begin, (int)len, bytes, special_end);
return len;
}
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
static const char *name_csi_plain[] = {
"ICH", "CUU", "CUD", "CUF", "CUB", "CNL", "CPL", "CHA", "CUP", "CHT", "ED", "EL", "IL", "DL", "EF", "EA",
"DCH", "SSE", "CPR", "SU", "SD", "NP", "PP", "CTC", "ECH", "CVT", "CBT", "SRS", "PTX", "SDS", "SIMD",NULL,
"HPA", "HPR", "REP", "DA", "VPA", "VPR", "HVP", "TBC", "SM", "MC", "HPB", "VPB", "RM", "SGR", "DSR", "DAQ",
};
/*0 4 8 B */
static const int newline_csi_plain[] = {
0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
};
static int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user)
{
const char *name = NULL;
if(!leader && !intermed && command < 0x70)
name = name_csi_plain[command - 0x40];
else if(leader && streq(leader, "?") && !intermed) {
/* DEC */
switch(command) {
case 'h': name = "DECSM"; break;
case 'l': name = "DECRM"; break;
}
if(name)
leader = NULL;
}
if(!leader && !intermed && command < 0x70 && newline_csi_plain[command - 0x40])
printf("\n");
if(name)
printf("%s%s", special_begin, name);
else
printf("%sCSI", special_begin);
if(leader && leader[0])
printf(" %s", leader);
{
int i;
for(i = 0; i < argcount; i++) {
printf(i ? "," : " ");
}
if(args[i] == CSI_ARG_MISSING)
printf("*");
else {
while(CSI_ARG_HAS_MORE(args[i]))
printf("%ld+", CSI_ARG(args[i++]));
printf("%ld", CSI_ARG(args[i]));
}
}
if(intermed && intermed[0])
printf(" %s", intermed);
if(name)
printf("%s", special_end);
else
printf(" %c%s", command, special_end);
return 1;
}
static int parser_osc(const char *command, size_t cmdlen, void *user)
{
printf("%sOSC %.*s%s", special_begin, (int)cmdlen, command, special_end);
return 1;
}
static int parser_dcs(const char *command, size_t cmdlen, void *user)
{
printf("%sDCS %.*s%s", special_begin, (int)cmdlen, command, special_end);
return 1;
}
static VTermParserCallbacks parser_cbs = {
&parser_text, /* text */
&parser_control, /* control */
&parser_escape, /* escape */
&parser_csi, /* csi */
&parser_osc, /* osc */
&parser_dcs, /* dcs */
NULL /* resize */
};
int main(int argc, char *argv[])
{
int use_colour = isatty(1);
const char *file;
int fd;
VTerm *vt;
int len;
char buffer[1024];
int opt;
while((opt = getopt(argc, argv, "c")) != -1) {
switch(opt) {
case 'c': use_colour = 1; break;
}
}
file = argv[optind++];
if(!file || streq(file, "-"))
fd = 0; /* stdin */
else {
fd = open(file, O_RDONLY);
if(fd == -1) {
fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno));
exit(1);
}
}
if(use_colour) {
special_begin = "\x1b[7m{";
special_end = "}\x1b[m";
}
/* Size matters not for the parser */
vt = vterm_new(25, 80);
vterm_set_utf8(vt, 1);
vterm_parser_set_callbacks(vt, &parser_cbs, NULL);
while((len = read(fd, buffer, sizeof(buffer))) > 0) {
vterm_input_write(vt, buffer, len);
}
printf("\n");
close(fd);
vterm_free(vt);
return 0;
}

11
src/libvterm/doc/URLs Normal file
View File

@@ -0,0 +1,11 @@
ECMA-48:
http://www.ecma-international.org/publications/standards/Ecma-048.htm
Xterm Control Sequences:
http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
Digital VT100 User Guide:
http://vt100.net/docs/vt100-ug/
Digital VT220 Programmer Reference Manual
http://vt100.net/docs/vt220-rm/

226
src/libvterm/doc/seqs.txt Normal file
View File

@@ -0,0 +1,226 @@
Sequences documented in parens are implicit ones from parser.c, which move
between states.
1 = VT100
2 = VT220
3 = VT320
C0 controls
123 0x00 = NUL
123 0x07 = BEL
123 0x08 = BS
123 0x09 = HT
123 0x0A = LF
123 0x0B = VT
123 0x0C = FF
123 0x0D = CR
123 0x0E = LS1
123 0x0F = LS0
(0x18 = CAN)
(0x1A = SUB)
(0x1B = ESC)
123 0x7f = DEL (ignored)
C1 controls
123 0x84 = IND
123 0x85 = NEL
123 0x88 = HTS
123 0x8D = RI
23 0x8e = SS2
23 0x8f = SS3
(0x90 = DCS)
(0x9B = CSI)
(0x9C = ST)
(0x9D = OSC)
Escape sequences
- excluding sequences that are C1 aliases
123 ESC () = SCS, select character set (G0, G1)
23 ESC *+ = SCS, select character set (G2, G3)
123 ESC 7 = DECSC - save cursor
123 ESC 8 = DECRC - restore cursor
123 ESC # 3 = DECDHL, double-height line (top half)
123 ESC # 4 = DECDHL, double-height line (bottom half)
123 ESC # 5 = DECSWL, single-width single-height line
123 ESC # 6 = DECDWL, double-width single-height line
123 ESC # 8 = DECALN
123 ESC < = Ignored (used by VT100 to exit VT52 mode)
123 ESC = = DECKPAM, keypad application mode
123 ESC > = DECKPNM, keypad numeric mode
23 ESC Sp F = S7C1T
23 ESC Sp G = S8C1T
(ESC P = DCS)
(ESC [ = CSI)
(ESC \ = ST)
(ESC ] = OSC)
123 ESC c = RIS, reset initial state
3 ESC n = LS2
3 ESC o = LS3
3 ESC ~ = LS1R
3 ESC } = LS2R
3 ESC | = LS3R
DCSes
3 DCS $ q ST = DECRQSS
3 m = Request SGR
Sp q = Request DECSCUSR
3 " q = Request DECSCA
3 r = Request DECSTBM
s = Request DECSLRM
CSIs
23 CSI @ = ICH
123 CSI A = CUU
123 CSI B = CUD
123 CSI C = CUF
123 CSI D = CUB
CSI E = CNL
CSI F = CPL
CSI G = CHA
123 CSI H = CUP
CSI I = CHT
123 CSI J = ED
23 CSI ? J = DECSED, selective erase in display
123 CSI K = EL
23 CSI ? K = DECSEL, selective erase in line
23 CSI L = IL
23 CSI M = DL
23 CSI P = DCH
CSI S = SU
CSI T = SD
23 CSI X = ECH
CSI Z = CBT
CSI ` = HPA
CSI a = HPR
123 CSI c = DA, device attributes
123 0 = DA
23 CSI > c = DECSDA
23 0 = SDA
CSI d = VPA
CSI e = VPR
123 CSI f = HVP
123 CSI g = TBC
123 CSI h = SM, Set mode
123 CSI ? h = DECSM, DEC set mode
CSI j = HPB
CSI k = VPB
123 CSI l = RM, Reset mode
123 CSI ? l = DECRM, DEC reset mode
123 CSI m = SGR, Set Graphic Rendition
123 CSI n = DSR, Device Status Report
23 5 = operating status
23 6 = CPR = cursor position
23 CSI ? n = DECDSR; behaves as DSR but uses CSI ? instead of CSI to respond
23 CSI ! p = DECSTR, soft terminal reset
3 CSI ? $ p = DECRQM, request mode
CSI Sp q = DECSCUSR (odd numbers blink, even numbers solid)
1 or 2 = block
3 or 4 = underline
5 or 6 = I-beam to left
23 CSI " q = DECSCA, select character attributes
123 CSI r = DECSTBM
CSI s = DECSLRM
CSI ' } = DECIC
CSI ' ~ = DECDC
OSCs
OSC 0; = Set icon name and title
OSC 1; = Set icon name
OSC 2; = Set title
Standard modes
23 SM 4 = IRM
123 SM 20 = NLM, linefeed/newline
DEC modes
123 DECSM 1 = DECCKM, cursor keys
123 DECSM 5 = DECSCNM, screen
123 DECSM 6 = DECOM, origin
123 DECSM 7 = DECAWM, autowrap
DECSM 12 = Cursor blink
23 DECSM 25 = DECTCEM, text cursor enable
DECSM 69 = DECVSSM, vertical screen split
DECSM 1000 = Mouse click/release tracking
DECSM 1002 = Mouse click/release/drag tracking
DECSM 1003 = Mouse all movements tracking
DECSM 1005 = Mouse protocol extended (UTF-8) - not recommended
DECSM 1006 = Mouse protocol SGR
DECSM 1015 = Mouse protocol rxvt
DECSM 1047 = Altscreen
DECSM 1048 = Save cursor
DECSM 1049 = 1047 + 1048
DECSM 2004 = Bracketed paste
Graphic Renditions
123 SGR 0 = Reset
123 SGR 1 = Bold on
SGR 3 = Italic on
123 SGR 4 = Underline single
123 SGR 5 = Blink on
123 SGR 7 = Reverse on
SGR 9 = Strikethrough on
SGR 10-19 = Select font
SGR 21 = Underline double
23 SGR 22 = Bold off
SGR 23 = Italic off
23 SGR 24 = Underline off
23 SGR 25 = Blink off
23 SGR 27 = Reverse off
SGR 29 = Strikethrough off
SGR 30-37 = Foreground ANSI
SGR 38 = Foreground alternative palette
SGR 39 = Foreground default
SGR 40-47 = Background ANSI
SGR 48 = Background alternative palette
SGR 49 = Background default
SGR 90-97 = Foreground ANSI high-intensity
SGR 100-107 = Background ANSI high-intensity
The state storage used by ESC 7 and DECSM 1048/1049 is shared.
Unimplemented sequences:
The following sequences are not recognised by libvterm.
123 0x05 = ENQ
3 0x11 = DC1 (XON)
3 0x13 = DC3 (XOFF)
12 ESC Z = DECID, identify terminal
DCS $ q = [DECRQSS]
3 " p = Request DECSCL
3 $ } = Request DECSASD
3 $ ~ = Request DECSSDT
23 DCS { = DECDLD, down-line-loadable character set
23 DCS | = DECUDK, user-defined key
23 CSI i = DEC printer control
23 CSI " p = DECSCL, set compatibility level
1 CSI q = DECLL, load LEDs
3 CSI $ u = DECRQTSR, request terminal state report
3 1 = terminal state report
3 CSI & u = DECRQUPSS, request user-preferred supplemental set
3 CSI $ w = DECRQPSR, request presentation state report
3 1 = cursor information report
3 2 = tab stop report
1 CSI x = DECREQTPARM, request terminal parameters
123 CSI y = DECTST, invoke confidence test
3 CSI $ } = DECSASD, select active status display
3 CSI $ ~ = DECSSDT, select status line type
23 SM 2 = KAM, keyboard action
123 SM 12 = SRM, send/receive
123 DECSM 2 = DECANM, ANSI/VT52
123 DECSM 3 = DECCOLM, 132 column
123 DECSM 4 = DECSCLM, scrolling
123 DECSM 8 = DECARM, auto-repeat
12 DECSM 9 = DECINLM, interlace
23 DECSM 18 = DECPFF, print form feed
23 DECSM 19 = DECPEX, print extent
23 DECSM 42 = DECNRCM, national/multinational character

View File

@@ -0,0 +1,370 @@
/*
* NOTE: This is a MODIFIED version of libvterm, see the README file.
*/
#ifndef __VTERM_H__
#define __VTERM_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include "vterm_keycodes.h"
typedef struct VTerm VTerm;
typedef struct VTermState VTermState;
typedef struct VTermScreen VTermScreen;
/* Specifies a screen point. */
typedef struct {
int row;
int col;
} VTermPos;
/*
* Some small utility functions; we can just keep these static here.
*/
/*
* Order points by on-screen flow order:
* Return < 0 if "a" is before "b"
* Return 0 if "a" and "b" are equal
* Return > 0 if "a" is after "b".
*/
int vterm_pos_cmp(VTermPos a, VTermPos b);
#if defined(DEFINE_INLINES) || USE_INLINE
INLINE int vterm_pos_cmp(VTermPos a, VTermPos b)
{
return (a.row == b.row) ? a.col - b.col : a.row - b.row;
}
#endif
/* Specifies a rectangular screen area. */
typedef struct {
int start_row;
int end_row;
int start_col;
int end_col;
} VTermRect;
/* Return true if the rect "r" contains the point "p". */
int vterm_rect_contains(VTermRect r, VTermPos p);
#if defined(DEFINE_INLINES) || USE_INLINE
INLINE int vterm_rect_contains(VTermRect r, VTermPos p)
{
return p.row >= r.start_row && p.row < r.end_row &&
p.col >= r.start_col && p.col < r.end_col;
}
#endif
/* Move "rect" "row_delta" down and "col_delta" right.
* Does not check boundaries. */
void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta);
#if defined(DEFINE_INLINES) || USE_INLINE
INLINE void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta)
{
rect->start_row += row_delta; rect->end_row += row_delta;
rect->start_col += col_delta; rect->end_col += col_delta;
}
#endif
typedef struct {
uint8_t red, green, blue;
} VTermColor;
typedef enum {
/* VTERM_VALUETYPE_NONE = 0 */
VTERM_VALUETYPE_BOOL = 1,
VTERM_VALUETYPE_INT,
VTERM_VALUETYPE_STRING,
VTERM_VALUETYPE_COLOR
} VTermValueType;
typedef union {
int boolean;
int number;
char *string;
VTermColor color;
} VTermValue;
typedef enum {
/* VTERM_ATTR_NONE = 0 */
VTERM_ATTR_BOLD = 1, /* bool: 1, 22 */
VTERM_ATTR_UNDERLINE, /* number: 4, 21, 24 */
VTERM_ATTR_ITALIC, /* bool: 3, 23 */
VTERM_ATTR_BLINK, /* bool: 5, 25 */
VTERM_ATTR_REVERSE, /* bool: 7, 27 */
VTERM_ATTR_STRIKE, /* bool: 9, 29 */
VTERM_ATTR_FONT, /* number: 10-19 */
VTERM_ATTR_FOREGROUND, /* color: 30-39 90-97 */
VTERM_ATTR_BACKGROUND /* color: 40-49 100-107 */
} VTermAttr;
typedef enum {
/* VTERM_PROP_NONE = 0 */
VTERM_PROP_CURSORVISIBLE = 1, /* bool */
VTERM_PROP_CURSORBLINK, /* bool */
VTERM_PROP_ALTSCREEN, /* bool */
VTERM_PROP_TITLE, /* string */
VTERM_PROP_ICONNAME, /* string */
VTERM_PROP_REVERSE, /* bool */
VTERM_PROP_CURSORSHAPE, /* number */
VTERM_PROP_MOUSE /* number */
} VTermProp;
enum {
VTERM_PROP_CURSORSHAPE_BLOCK = 1,
VTERM_PROP_CURSORSHAPE_UNDERLINE,
VTERM_PROP_CURSORSHAPE_BAR_LEFT
};
enum {
VTERM_PROP_MOUSE_NONE = 0,
VTERM_PROP_MOUSE_CLICK,
VTERM_PROP_MOUSE_DRAG,
VTERM_PROP_MOUSE_MOVE
};
typedef struct {
const uint32_t *chars;
int width;
unsigned int protected_cell:1; /* DECSCA-protected against DECSEL/DECSED */
unsigned int dwl:1; /* DECDWL or DECDHL double-width line */
unsigned int dhl:2; /* DECDHL double-height line (1=top 2=bottom) */
} VTermGlyphInfo;
typedef struct {
unsigned int doublewidth:1; /* DECDWL or DECDHL line */
unsigned int doubleheight:2; /* DECDHL line (1=top 2=bottom) */
} VTermLineInfo;
typedef struct {
/* libvterm relies on the allocated memory to be zeroed out before it is
* returned by the allocator. */
void *(*malloc)(size_t size, void *allocdata);
void (*free)(void *ptr, void *allocdata);
} VTermAllocatorFunctions;
/* Allocate and initialize a new terminal with default allocators. */
VTerm *vterm_new(int rows, int cols);
/* Allocate and initialize a new terminal with specified allocators. */
VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata);
/* Free and cleanup a terminal and all its data. */
void vterm_free(VTerm* vt);
void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp);
void vterm_set_size(VTerm *vt, int rows, int cols);
int vterm_get_utf8(const VTerm *vt);
void vterm_set_utf8(VTerm *vt, int is_utf8);
size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len);
size_t vterm_output_get_buffer_size(const VTerm *vt);
size_t vterm_output_get_buffer_current(const VTerm *vt);
size_t vterm_output_get_buffer_remaining(const VTerm *vt);
size_t vterm_output_read(VTerm *vt, char *buffer, size_t len);
void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod);
void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod);
void vterm_keyboard_start_paste(VTerm *vt);
void vterm_keyboard_end_paste(VTerm *vt);
void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod);
void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod);
/* ------------
* Parser layer
* ------------ */
/* Flag to indicate non-final subparameters in a single CSI parameter.
* Consider
* CSI 1;2:3:4;5a
* 1 4 and 5 are final.
* 2 and 3 are non-final and will have this bit set
*
* Don't confuse this with the final byte of the CSI escape; 'a' in this case.
*/
#define CSI_ARG_FLAG_MORE (1<<31)
#define CSI_ARG_MASK (~(1<<31))
#define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE)
#define CSI_ARG(a) ((a) & CSI_ARG_MASK)
/* Can't use -1 to indicate a missing argument; use this instead */
#define CSI_ARG_MISSING ((1UL<<31)-1)
#define CSI_ARG_IS_MISSING(a) (CSI_ARG(a) == CSI_ARG_MISSING)
#define CSI_ARG_OR(a,def) (CSI_ARG(a) == CSI_ARG_MISSING ? (def) : CSI_ARG(a))
#define CSI_ARG_COUNT(a) (CSI_ARG(a) == CSI_ARG_MISSING || CSI_ARG(a) == 0 ? 1 : CSI_ARG(a))
typedef struct {
int (*text)(const char *bytes, size_t len, void *user);
int (*control)(unsigned char control, void *user);
int (*escape)(const char *bytes, size_t len, void *user);
int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);
int (*osc)(const char *command, size_t cmdlen, void *user);
int (*dcs)(const char *command, size_t cmdlen, void *user);
int (*resize)(int rows, int cols, void *user);
} VTermParserCallbacks;
void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user);
void *vterm_parser_get_cbdata(VTerm *vt);
/* -----------
* State layer
* ----------- */
typedef struct {
int (*putglyph)(VTermGlyphInfo *info, VTermPos pos, void *user);
int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user);
int (*scrollrect)(VTermRect rect, int downward, int rightward, void *user);
int (*moverect)(VTermRect dest, VTermRect src, void *user);
int (*erase)(VTermRect rect, int selective, void *user);
int (*initpen)(void *user);
int (*setpenattr)(VTermAttr attr, VTermValue *val, void *user);
int (*settermprop)(VTermProp prop, VTermValue *val, void *user);
int (*bell)(void *user);
int (*resize)(int rows, int cols, VTermPos *delta, void *user);
int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user);
} VTermStateCallbacks;
VTermState *vterm_obtain_state(VTerm *vt);
void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user);
void *vterm_state_get_cbdata(VTermState *state);
/* Only invokes control, csi, osc, dcs */
void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermParserCallbacks *fallbacks, void *user);
void *vterm_state_get_unrecognised_fbdata(VTermState *state);
void vterm_state_reset(VTermState *state, int hard);
void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos);
void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg);
void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col);
void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg);
void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col);
void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright);
int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val);
int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val);
const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row);
/* ------------
* Screen layer
* ------------ */
typedef struct {
unsigned int bold : 1;
unsigned int underline : 2;
unsigned int italic : 1;
unsigned int blink : 1;
unsigned int reverse : 1;
unsigned int strike : 1;
unsigned int font : 4; /* 0 to 9 */
unsigned int dwl : 1; /* On a DECDWL or DECDHL line */
unsigned int dhl : 2; /* On a DECDHL line (1=top 2=bottom) */
} VTermScreenCellAttrs;
typedef struct {
#define VTERM_MAX_CHARS_PER_CELL 6
uint32_t chars[VTERM_MAX_CHARS_PER_CELL];
char width;
VTermScreenCellAttrs attrs;
VTermColor fg, bg;
} VTermScreenCell;
/* All fields are optional, NULL when not used. */
typedef struct {
int (*damage)(VTermRect rect, void *user);
int (*moverect)(VTermRect dest, VTermRect src, void *user);
int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user);
int (*settermprop)(VTermProp prop, VTermValue *val, void *user);
int (*bell)(void *user);
int (*resize)(int rows, int cols, void *user);
int (*sb_pushline)(int cols, const VTermScreenCell *cells, void *user);
int (*sb_popline)(int cols, VTermScreenCell *cells, void *user);
} VTermScreenCallbacks;
VTermScreen *vterm_obtain_screen(VTerm *vt);
/*
* Install screen callbacks. These are invoked when the screen contents is
* changed. "user" is passed into to the callback.
*/
void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user);
void *vterm_screen_get_cbdata(VTermScreen *screen);
/* Only invokes control, csi, osc, dcs */
void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user);
void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen);
void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen);
typedef enum {
VTERM_DAMAGE_CELL, /* every cell */
VTERM_DAMAGE_ROW, /* entire rows */
VTERM_DAMAGE_SCREEN, /* entire screen */
VTERM_DAMAGE_SCROLL /* entire screen + scrollrect */
} VTermDamageSize;
void vterm_screen_flush_damage(VTermScreen *screen);
void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size);
void vterm_screen_reset(VTermScreen *screen, int hard);
/* Neither of these functions NUL-terminate the buffer */
size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect);
size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect);
typedef enum {
VTERM_ATTR_BOLD_MASK = 1 << 0,
VTERM_ATTR_UNDERLINE_MASK = 1 << 1,
VTERM_ATTR_ITALIC_MASK = 1 << 2,
VTERM_ATTR_BLINK_MASK = 1 << 3,
VTERM_ATTR_REVERSE_MASK = 1 << 4,
VTERM_ATTR_STRIKE_MASK = 1 << 5,
VTERM_ATTR_FONT_MASK = 1 << 6,
VTERM_ATTR_FOREGROUND_MASK = 1 << 7,
VTERM_ATTR_BACKGROUND_MASK = 1 << 8
} VTermAttrMask;
int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs);
int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell);
int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos);
/* ---------
* Utilities
* --------- */
VTermValueType vterm_get_attr_type(VTermAttr attr);
VTermValueType vterm_get_prop_type(VTermProp prop);
void vterm_scroll_rect(VTermRect rect,
int downward,
int rightward,
int (*moverect)(VTermRect src, VTermRect dest, void *user),
int (*eraserect)(VTermRect rect, int selective, void *user),
void *user);
void vterm_copy_cells(VTermRect dest,
VTermRect src,
void (*copycell)(VTermPos dest, VTermPos src, void *user),
void *user);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,58 @@
#ifndef __VTERM_INPUT_H__
#define __VTERM_INPUT_H__
typedef enum {
VTERM_MOD_NONE = 0x00,
VTERM_MOD_SHIFT = 0x01,
VTERM_MOD_ALT = 0x02,
VTERM_MOD_CTRL = 0x04
} VTermModifier;
typedef enum {
VTERM_KEY_NONE,
VTERM_KEY_ENTER,
VTERM_KEY_TAB,
VTERM_KEY_BACKSPACE,
VTERM_KEY_ESCAPE,
VTERM_KEY_UP,
VTERM_KEY_DOWN,
VTERM_KEY_LEFT,
VTERM_KEY_RIGHT,
VTERM_KEY_INS,
VTERM_KEY_DEL,
VTERM_KEY_HOME,
VTERM_KEY_END,
VTERM_KEY_PAGEUP,
VTERM_KEY_PAGEDOWN,
VTERM_KEY_FUNCTION_0 = 256,
VTERM_KEY_FUNCTION_MAX = VTERM_KEY_FUNCTION_0 + 255,
VTERM_KEY_KP_0,
VTERM_KEY_KP_1,
VTERM_KEY_KP_2,
VTERM_KEY_KP_3,
VTERM_KEY_KP_4,
VTERM_KEY_KP_5,
VTERM_KEY_KP_6,
VTERM_KEY_KP_7,
VTERM_KEY_KP_8,
VTERM_KEY_KP_9,
VTERM_KEY_KP_MULT,
VTERM_KEY_KP_PLUS,
VTERM_KEY_KP_COMMA,
VTERM_KEY_KP_MINUS,
VTERM_KEY_KP_PERIOD,
VTERM_KEY_KP_DIVIDE,
VTERM_KEY_KP_ENTER,
VTERM_KEY_KP_EQUAL,
VTERM_KEY_MAX /* Must be last */
} VTermKey;
#define VTERM_KEY_FUNCTION(n) (VTERM_KEY_FUNCTION_0+(n))
#endif

232
src/libvterm/src/encoding.c Normal file
View File

@@ -0,0 +1,232 @@
#include "vterm_internal.h"
#define UNICODE_INVALID 0xFFFD
#if defined(DEBUG) && DEBUG > 1
# define DEBUG_PRINT_UTF8
#endif
struct UTF8DecoderData {
/* number of bytes remaining in this codepoint */
int bytes_remaining;
/* number of bytes total in this codepoint once it's finished
(for detecting overlongs) */
int bytes_total;
int this_cp;
};
static void init_utf8(VTermEncoding *enc UNUSED, void *data_)
{
struct UTF8DecoderData *data = data_;
data->bytes_remaining = 0;
data->bytes_total = 0;
}
static void decode_utf8(VTermEncoding *enc UNUSED, void *data_,
uint32_t cp[], int *cpi, int cplen,
const char bytes[], size_t *pos, size_t bytelen)
{
struct UTF8DecoderData *data = data_;
#ifdef DEBUG_PRINT_UTF8
printf("BEGIN UTF-8\n");
#endif
for(; *pos < bytelen && *cpi < cplen; (*pos)++) {
unsigned char c = bytes[*pos];
#ifdef DEBUG_PRINT_UTF8
printf(" pos=%zd c=%02x rem=%d\n", *pos, c, data->bytes_remaining);
#endif
if(c < 0x20) /* C0 */
return;
else if(c >= 0x20 && c < 0x7f) {
if(data->bytes_remaining)
cp[(*cpi)++] = UNICODE_INVALID;
cp[(*cpi)++] = c;
#ifdef DEBUG_PRINT_UTF8
printf(" UTF-8 char: U+%04x\n", c);
#endif
data->bytes_remaining = 0;
}
else if(c == 0x7f) /* DEL */
return;
else if(c >= 0x80 && c < 0xc0) {
if(!data->bytes_remaining) {
cp[(*cpi)++] = UNICODE_INVALID;
continue;
}
data->this_cp <<= 6;
data->this_cp |= c & 0x3f;
data->bytes_remaining--;
if(!data->bytes_remaining) {
#ifdef DEBUG_PRINT_UTF8
printf(" UTF-8 raw char U+%04x bytelen=%d ", data->this_cp, data->bytes_total);
#endif
/* Check for overlong sequences */
switch(data->bytes_total) {
case 2:
if(data->this_cp < 0x0080) data->this_cp = UNICODE_INVALID;
break;
case 3:
if(data->this_cp < 0x0800) data->this_cp = UNICODE_INVALID;
break;
case 4:
if(data->this_cp < 0x10000) data->this_cp = UNICODE_INVALID;
break;
case 5:
if(data->this_cp < 0x200000) data->this_cp = UNICODE_INVALID;
break;
case 6:
if(data->this_cp < 0x4000000) data->this_cp = UNICODE_INVALID;
break;
}
/* Now look for plain invalid ones */
if((data->this_cp >= 0xD800 && data->this_cp <= 0xDFFF) ||
data->this_cp == 0xFFFE ||
data->this_cp == 0xFFFF)
data->this_cp = UNICODE_INVALID;
#ifdef DEBUG_PRINT_UTF8
printf(" char: U+%04x\n", data->this_cp);
#endif
cp[(*cpi)++] = data->this_cp;
}
}
else if(c >= 0xc0 && c < 0xe0) {
if(data->bytes_remaining)
cp[(*cpi)++] = UNICODE_INVALID;
data->this_cp = c & 0x1f;
data->bytes_total = 2;
data->bytes_remaining = 1;
}
else if(c >= 0xe0 && c < 0xf0) {
if(data->bytes_remaining)
cp[(*cpi)++] = UNICODE_INVALID;
data->this_cp = c & 0x0f;
data->bytes_total = 3;
data->bytes_remaining = 2;
}
else if(c >= 0xf0 && c < 0xf8) {
if(data->bytes_remaining)
cp[(*cpi)++] = UNICODE_INVALID;
data->this_cp = c & 0x07;
data->bytes_total = 4;
data->bytes_remaining = 3;
}
else if(c >= 0xf8 && c < 0xfc) {
if(data->bytes_remaining)
cp[(*cpi)++] = UNICODE_INVALID;
data->this_cp = c & 0x03;
data->bytes_total = 5;
data->bytes_remaining = 4;
}
else if(c >= 0xfc && c < 0xfe) {
if(data->bytes_remaining)
cp[(*cpi)++] = UNICODE_INVALID;
data->this_cp = c & 0x01;
data->bytes_total = 6;
data->bytes_remaining = 5;
}
else {
cp[(*cpi)++] = UNICODE_INVALID;
}
}
}
static VTermEncoding encoding_utf8 = {
&init_utf8, /* init */
&decode_utf8 /* decode */
};
static void decode_usascii(VTermEncoding *enc UNUSED, void *data UNUSED,
uint32_t cp[], int *cpi, int cplen,
const char bytes[], size_t *pos, size_t bytelen)
{
int is_gr = bytes[*pos] & 0x80;
for(; *pos < bytelen && *cpi < cplen; (*pos)++) {
unsigned char c = bytes[*pos] ^ is_gr;
if(c < 0x20 || c == 0x7f || c >= 0x80)
return;
cp[(*cpi)++] = c;
}
}
static VTermEncoding encoding_usascii = {
NULL, /* init */
&decode_usascii /* decode */
};
struct StaticTableEncoding {
const VTermEncoding enc;
const uint32_t chars[128];
};
static void decode_table(VTermEncoding *enc, void *data UNUSED,
uint32_t cp[], int *cpi, int cplen,
const char bytes[], size_t *pos, size_t bytelen)
{
struct StaticTableEncoding *table = (struct StaticTableEncoding *)enc;
int is_gr = bytes[*pos] & 0x80;
for(; *pos < bytelen && *cpi < cplen; (*pos)++) {
unsigned char c = bytes[*pos] ^ is_gr;
if(c < 0x20 || c == 0x7f || c >= 0x80)
return;
if(table->chars[c])
cp[(*cpi)++] = table->chars[c];
else
cp[(*cpi)++] = c;
}
}
#include "encoding/DECdrawing.inc"
#include "encoding/uk.inc"
static struct {
VTermEncodingType type;
char designation;
VTermEncoding *enc;
}
encodings[] = {
{ ENC_UTF8, 'u', &encoding_utf8 },
{ ENC_SINGLE_94, '0', (VTermEncoding*)&encoding_DECdrawing },
{ ENC_SINGLE_94, 'A', (VTermEncoding*)&encoding_uk },
{ ENC_SINGLE_94, 'B', &encoding_usascii },
{ 0 },
};
/* This ought to be INTERNAL but isn't because it's used by unit testing */
VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation)
{
int i;
for(i = 0; encodings[i].designation; i++)
if(encodings[i].type == type && encodings[i].designation == designation)
return encodings[i].enc;
return NULL;
}

View File

@@ -0,0 +1,136 @@
static const struct StaticTableEncoding encoding_DECdrawing = {
{
NULL, /* init */
&decode_table /* decode */
},
{
0x0, /* 0 */
0x0, /* 1 */
0x0, /* 2 */
0x0, /* 3 */
0x0, /* 4 */
0x0, /* 5 */
0x0, /* 6 */
0x0, /* 7 */
0x0, /* 8 */
0x0, /* 9 */
0x0, /* 10 */
0x0, /* 11 */
0x0, /* 12 */
0x0, /* 13 */
0x0, /* 14 */
0x0, /* 15 */
0x0, /* 16 */
0x0, /* 17 */
0x0, /* 18 */
0x0, /* 19 */
0x0, /* 20 */
0x0, /* 21 */
0x0, /* 22 */
0x0, /* 23 */
0x0, /* 24 */
0x0, /* 25 */
0x0, /* 26 */
0x0, /* 27 */
0x0, /* 28 */
0x0, /* 29 */
0x0, /* 30 */
0x0, /* 31 */
0x0, /* 32 */
0x0, /* 33 */
0x0, /* 34 */
0x0, /* 35 */
0x0, /* 36 */
0x0, /* 37 */
0x0, /* 38 */
0x0, /* 39 */
0x0, /* 40 */
0x0, /* 41 */
0x0, /* 42 */
0x0, /* 43 */
0x0, /* 44 */
0x0, /* 45 */
0x0, /* 46 */
0x0, /* 47 */
0x0, /* 48 */
0x0, /* 49 */
0x0, /* 50 */
0x0, /* 51 */
0x0, /* 52 */
0x0, /* 53 */
0x0, /* 54 */
0x0, /* 55 */
0x0, /* 56 */
0x0, /* 57 */
0x0, /* 58 */
0x0, /* 59 */
0x0, /* 60 */
0x0, /* 61 */
0x0, /* 62 */
0x0, /* 63 */
0x0, /* 64 */
0x0, /* 65 */
0x0, /* 66 */
0x0, /* 67 */
0x0, /* 68 */
0x0, /* 69 */
0x0, /* 70 */
0x0, /* 71 */
0x0, /* 72 */
0x0, /* 73 */
0x0, /* 74 */
0x0, /* 75 */
0x0, /* 76 */
0x0, /* 77 */
0x0, /* 78 */
0x0, /* 79 */
0x0, /* 80 */
0x0, /* 81 */
0x0, /* 82 */
0x0, /* 83 */
0x0, /* 84 */
0x0, /* 85 */
0x0, /* 86 */
0x0, /* 87 */
0x0, /* 88 */
0x0, /* 89 */
0x0, /* 90 */
0x0, /* 91 */
0x0, /* 92 */
0x0, /* 93 */
0x0, /* 94 */
0x0, /* 95 */
0x25C6, /* 96 */
0x2592, /* 97 */
0x2409, /* 98 */
0x240C, /* 99 */
0x240D, /* 100 */
0x240A, /* 101 */
0x00B0, /* 102 */
0x00B1, /* 103 */
0x2424, /* 104 */
0x240B, /* 105 */
0x2518, /* 106 */
0x2510, /* 107 */
0x250C, /* 108 */
0x2514, /* 109 */
0x253C, /* 110 */
0x23BA, /* 111 */
0x23BB, /* 112 */
0x2500, /* 113 */
0x23BC, /* 114 */
0x23BD, /* 115 */
0x251C, /* 116 */
0x2524, /* 117 */
0x2534, /* 118 */
0x252C, /* 119 */
0x2502, /* 120 */
0x2A7D, /* 121 */
0x2A7E, /* 122 */
0x03C0, /* 123 */
0x2260, /* 124 */
0x00A3, /* 125 */
0x00B7, /* 126 */
0x0, /* 127 */
}
};

View File

@@ -0,0 +1,31 @@
6/0 = U+25C6 # BLACK DIAMOND
6/1 = U+2592 # MEDIUM SHADE (checkerboard)
6/2 = U+2409 # SYMBOL FOR HORIZONTAL TAB
6/3 = U+240C # SYMBOL FOR FORM FEED
6/4 = U+240D # SYMBOL FOR CARRIAGE RETURN
6/5 = U+240A # SYMBOL FOR LINE FEED
6/6 = U+00B0 # DEGREE SIGN
6/7 = U+00B1 # PLUS-MINUS SIGN (plus or minus)
6/8 = U+2424 # SYMBOL FOR NEW LINE
6/9 = U+240B # SYMBOL FOR VERTICAL TAB
6/10 = U+2518 # BOX DRAWINGS LIGHT UP AND LEFT (bottom-right corner)
6/11 = U+2510 # BOX DRAWINGS LIGHT DOWN AND LEFT (top-right corner)
6/12 = U+250C # BOX DRAWINGS LIGHT DOWN AND RIGHT (top-left corner)
6/13 = U+2514 # BOX DRAWINGS LIGHT UP AND RIGHT (bottom-left corner)
6/14 = U+253C # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL (crossing lines)
6/15 = U+23BA # HORIZONTAL SCAN LINE-1
7/0 = U+23BB # HORIZONTAL SCAN LINE-3
7/1 = U+2500 # BOX DRAWINGS LIGHT HORIZONTAL
7/2 = U+23BC # HORIZONTAL SCAN LINE-7
7/3 = U+23BD # HORIZONTAL SCAN LINE-9
7/4 = U+251C # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
7/5 = U+2524 # BOX DRAWINGS LIGHT VERTICAL AND LEFT
7/6 = U+2534 # BOX DRAWINGS LIGHT UP AND HORIZONTAL
7/7 = U+252C # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
7/8 = U+2502 # BOX DRAWINGS LIGHT VERTICAL
7/9 = U+2A7D # LESS-THAN OR SLANTED EQUAL-TO
7/10 = U+2A7E # GREATER-THAN OR SLANTED EQUAL-TO
7/11 = U+03C0 # GREEK SMALL LETTER PI
7/12 = U+2260 # NOT EQUAL TO
7/13 = U+00A3 # POUND SIGN
7/14 = U+00B7 # MIDDLE DOT

View File

@@ -0,0 +1,136 @@
static const struct StaticTableEncoding encoding_uk = {
{
NULL, /* init */
&decode_table /* decode */
},
{
0x0, /* 0 */
0x0, /* 1 */
0x0, /* 2 */
0x0, /* 3 */
0x0, /* 4 */
0x0, /* 5 */
0x0, /* 6 */
0x0, /* 7 */
0x0, /* 8 */
0x0, /* 9 */
0x0, /* 10 */
0x0, /* 11 */
0x0, /* 12 */
0x0, /* 13 */
0x0, /* 14 */
0x0, /* 15 */
0x0, /* 16 */
0x0, /* 17 */
0x0, /* 18 */
0x0, /* 19 */
0x0, /* 20 */
0x0, /* 21 */
0x0, /* 22 */
0x0, /* 23 */
0x0, /* 24 */
0x0, /* 25 */
0x0, /* 26 */
0x0, /* 27 */
0x0, /* 28 */
0x0, /* 29 */
0x0, /* 30 */
0x0, /* 31 */
0x0, /* 32 */
0x0, /* 33 */
0x0, /* 34 */
0x00a3, /* 35 */
0x0, /* 36 */
0x0, /* 37 */
0x0, /* 38 */
0x0, /* 39 */
0x0, /* 40 */
0x0, /* 41 */
0x0, /* 42 */
0x0, /* 43 */
0x0, /* 44 */
0x0, /* 45 */
0x0, /* 46 */
0x0, /* 47 */
0x0, /* 48 */
0x0, /* 49 */
0x0, /* 50 */
0x0, /* 51 */
0x0, /* 52 */
0x0, /* 53 */
0x0, /* 54 */
0x0, /* 55 */
0x0, /* 56 */
0x0, /* 57 */
0x0, /* 58 */
0x0, /* 59 */
0x0, /* 60 */
0x0, /* 61 */
0x0, /* 62 */
0x0, /* 63 */
0x0, /* 64 */
0x0, /* 65 */
0x0, /* 66 */
0x0, /* 67 */
0x0, /* 68 */
0x0, /* 69 */
0x0, /* 70 */
0x0, /* 71 */
0x0, /* 72 */
0x0, /* 73 */
0x0, /* 74 */
0x0, /* 75 */
0x0, /* 76 */
0x0, /* 77 */
0x0, /* 78 */
0x0, /* 79 */
0x0, /* 80 */
0x0, /* 81 */
0x0, /* 82 */
0x0, /* 83 */
0x0, /* 84 */
0x0, /* 85 */
0x0, /* 86 */
0x0, /* 87 */
0x0, /* 88 */
0x0, /* 89 */
0x0, /* 90 */
0x0, /* 91 */
0x0, /* 92 */
0x0, /* 93 */
0x0, /* 94 */
0x0, /* 95 */
0x0, /* 96 */
0x0, /* 97 */
0x0, /* 98 */
0x0, /* 99 */
0x0, /* 100 */
0x0, /* 101 */
0x0, /* 102 */
0x0, /* 103 */
0x0, /* 104 */
0x0, /* 105 */
0x0, /* 106 */
0x0, /* 107 */
0x0, /* 108 */
0x0, /* 109 */
0x0, /* 110 */
0x0, /* 111 */
0x0, /* 112 */
0x0, /* 113 */
0x0, /* 114 */
0x0, /* 115 */
0x0, /* 116 */
0x0, /* 117 */
0x0, /* 118 */
0x0, /* 119 */
0x0, /* 120 */
0x0, /* 121 */
0x0, /* 122 */
0x0, /* 123 */
0x0, /* 124 */
0x0, /* 125 */
0x0, /* 126 */
0x0, /* 127 */
}
};

View File

@@ -0,0 +1 @@
2/3 = "£"

228
src/libvterm/src/keyboard.c Normal file
View File

@@ -0,0 +1,228 @@
#include "vterm_internal.h"
#include <stdio.h>
#include "utf8.h"
void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod)
{
int needs_CSIu;
/* The shift modifier is never important for Unicode characters
* apart from Space
*/
if(c != ' ')
mod &= ~VTERM_MOD_SHIFT;
if(mod == 0) {
/* Normal text - ignore just shift */
char str[6];
int seqlen = fill_utf8(c, str);
vterm_push_output_bytes(vt, str, seqlen);
return;
}
switch(c) {
/* Special Ctrl- letters that can't be represented elsewise */
case 'i': case 'j': case 'm': case '[':
needs_CSIu = 1;
break;
/* Ctrl-\ ] ^ _ don't need CSUu */
case '\\': case ']': case '^': case '_':
needs_CSIu = 0;
break;
/* Shift-space needs CSIu */
case ' ':
needs_CSIu = !!(mod & VTERM_MOD_SHIFT);
break;
/* All other characters needs CSIu except for letters a-z */
default:
needs_CSIu = (c < 'a' || c > 'z');
}
/* ALT we can just prefix with ESC; anything else requires CSI u */
if(needs_CSIu && (mod & ~VTERM_MOD_ALT)) {
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", c, mod+1);
return;
}
if(mod & VTERM_MOD_CTRL)
c &= 0x1f;
vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? ESC_S : "", c);
}
typedef struct {
enum {
KEYCODE_NONE,
KEYCODE_LITERAL,
KEYCODE_TAB,
KEYCODE_ENTER,
KEYCODE_SS3,
KEYCODE_CSI,
KEYCODE_CSI_CURSOR,
KEYCODE_CSINUM,
KEYCODE_KEYPAD
} type;
char literal;
int csinum;
} keycodes_s;
static keycodes_s keycodes[] = {
{ KEYCODE_NONE, 0, 0 }, /* NONE */
{ KEYCODE_ENTER, '\r', 0 }, /* ENTER */
{ KEYCODE_TAB, '\t', 0 }, /* TAB */
{ KEYCODE_LITERAL, '\x7f', 0 }, /* BACKSPACE == ASCII DEL */
{ KEYCODE_LITERAL, '\x1b', 0 }, /* ESCAPE */
{ KEYCODE_CSI_CURSOR, 'A', 0 }, /* UP */
{ KEYCODE_CSI_CURSOR, 'B', 0 }, /* DOWN */
{ KEYCODE_CSI_CURSOR, 'D', 0 }, /* LEFT */
{ KEYCODE_CSI_CURSOR, 'C', 0 }, /* RIGHT */
{ KEYCODE_CSINUM, '~', 2 }, /* INS */
{ KEYCODE_CSINUM, '~', 3 }, /* DEL */
{ KEYCODE_CSI_CURSOR, 'H', 0 }, /* HOME */
{ KEYCODE_CSI_CURSOR, 'F', 0 }, /* END */
{ KEYCODE_CSINUM, '~', 5 }, /* PAGEUP */
{ KEYCODE_CSINUM, '~', 6 }, /* PAGEDOWN */
};
static keycodes_s keycodes_fn[] = {
{ KEYCODE_NONE, 0, 0 }, /* F0 - shouldn't happen */
{ KEYCODE_CSI_CURSOR, 'P', 0 }, /* F1 */
{ KEYCODE_CSI_CURSOR, 'Q', 0 }, /* F2 */
{ KEYCODE_CSI_CURSOR, 'R', 0 }, /* F3 */
{ KEYCODE_CSI_CURSOR, 'S', 0 }, /* F4 */
{ KEYCODE_CSINUM, '~', 15 }, /* F5 */
{ KEYCODE_CSINUM, '~', 17 }, /* F6 */
{ KEYCODE_CSINUM, '~', 18 }, /* F7 */
{ KEYCODE_CSINUM, '~', 19 }, /* F8 */
{ KEYCODE_CSINUM, '~', 20 }, /* F9 */
{ KEYCODE_CSINUM, '~', 21 }, /* F10 */
{ KEYCODE_CSINUM, '~', 23 }, /* F11 */
{ KEYCODE_CSINUM, '~', 24 }, /* F12 */
};
static keycodes_s keycodes_kp[] = {
{ KEYCODE_KEYPAD, '0', 'p' }, /* KP_0 */
{ KEYCODE_KEYPAD, '1', 'q' }, /* KP_1 */
{ KEYCODE_KEYPAD, '2', 'r' }, /* KP_2 */
{ KEYCODE_KEYPAD, '3', 's' }, /* KP_3 */
{ KEYCODE_KEYPAD, '4', 't' }, /* KP_4 */
{ KEYCODE_KEYPAD, '5', 'u' }, /* KP_5 */
{ KEYCODE_KEYPAD, '6', 'v' }, /* KP_6 */
{ KEYCODE_KEYPAD, '7', 'w' }, /* KP_7 */
{ KEYCODE_KEYPAD, '8', 'x' }, /* KP_8 */
{ KEYCODE_KEYPAD, '9', 'y' }, /* KP_9 */
{ KEYCODE_KEYPAD, '*', 'j' }, /* KP_MULT */
{ KEYCODE_KEYPAD, '+', 'k' }, /* KP_PLUS */
{ KEYCODE_KEYPAD, ',', 'l' }, /* KP_COMMA */
{ KEYCODE_KEYPAD, '-', 'm' }, /* KP_MINUS */
{ KEYCODE_KEYPAD, '.', 'n' }, /* KP_PERIOD */
{ KEYCODE_KEYPAD, '/', 'o' }, /* KP_DIVIDE */
{ KEYCODE_KEYPAD, '\n', 'M' }, /* KP_ENTER */
{ KEYCODE_KEYPAD, '=', 'X' }, /* KP_EQUAL */
};
void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod)
{
keycodes_s k;
if(key == VTERM_KEY_NONE)
return;
if(key < VTERM_KEY_FUNCTION_0) {
if(key >= sizeof(keycodes)/sizeof(keycodes[0]))
return;
k = keycodes[key];
}
else if(key >= VTERM_KEY_FUNCTION_0 && key <= VTERM_KEY_FUNCTION_MAX) {
if((key - VTERM_KEY_FUNCTION_0) >= sizeof(keycodes_fn)/sizeof(keycodes_fn[0]))
return;
k = keycodes_fn[key - VTERM_KEY_FUNCTION_0];
}
else if(key >= VTERM_KEY_KP_0) {
if((key - VTERM_KEY_KP_0) >= sizeof(keycodes_kp)/sizeof(keycodes_kp[0]))
return;
k = keycodes_kp[key - VTERM_KEY_KP_0];
}
switch(k.type) {
case KEYCODE_NONE:
break;
case KEYCODE_TAB:
/* Shift-Tab is CSI Z but plain Tab is 0x09 */
if(mod == VTERM_MOD_SHIFT)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "Z");
else if(mod & VTERM_MOD_SHIFT)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%dZ", mod+1);
else
goto case_LITERAL;
break;
case KEYCODE_ENTER:
/* Enter is CRLF in newline mode, but just LF in linefeed */
if(vt->state->mode.newline)
vterm_push_output_sprintf(vt, "\r\n");
else
goto case_LITERAL;
break;
case KEYCODE_LITERAL: case_LITERAL:
if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL))
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod+1);
else
vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? ESC_S "%c" : "%c", k.literal);
break;
case KEYCODE_SS3: case_SS3:
if(mod == 0)
vterm_push_output_sprintf_ctrl(vt, C1_SS3, "%c", k.literal);
else
goto case_CSI;
break;
case KEYCODE_CSI: case_CSI:
if(mod == 0)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%c", k.literal);
else
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%d%c", mod + 1, k.literal);
break;
case KEYCODE_CSINUM:
if(mod == 0)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d%c", k.csinum, k.literal);
else
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%d%c", k.csinum, mod + 1, k.literal);
break;
case KEYCODE_CSI_CURSOR:
if(vt->state->mode.cursor)
goto case_SS3;
else
goto case_CSI;
case KEYCODE_KEYPAD:
if(vt->state->mode.keypad) {
k.literal = k.csinum;
goto case_SS3;
}
else
goto case_LITERAL;
}
}
void vterm_keyboard_start_paste(VTerm *vt)
{
if(vt->state->mode.bracketpaste)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "200~");
}
void vterm_keyboard_end_paste(VTerm *vt)
{
if(vt->state->mode.bracketpaste)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "201~");
}

96
src/libvterm/src/mouse.c Normal file
View File

@@ -0,0 +1,96 @@
#include "vterm_internal.h"
#include "utf8.h"
static void output_mouse(VTermState *state, int code, int pressed, int modifiers, int col, int row)
{
modifiers <<= 2;
switch(state->mouse_protocol) {
case MOUSE_X10:
if(col + 0x21 > 0xff)
col = 0xff - 0x21;
if(row + 0x21 > 0xff)
row = 0xff - 0x21;
if(!pressed)
code = 3;
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%c%c%c",
(code | modifiers) + 0x20, col + 0x21, row + 0x21);
break;
case MOUSE_UTF8:
{
char utf8[18]; size_t len = 0;
if(!pressed)
code = 3;
len += fill_utf8((code | modifiers) + 0x20, utf8 + len);
len += fill_utf8(col + 0x21, utf8 + len);
len += fill_utf8(row + 0x21, utf8 + len);
utf8[len] = 0;
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%s", utf8);
}
break;
case MOUSE_SGR:
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "<%d;%d;%d%c",
code | modifiers, col + 1, row + 1, pressed ? 'M' : 'm');
break;
case MOUSE_RXVT:
if(!pressed)
code = 3;
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%d;%d;%dM",
code | modifiers, col + 1, row + 1);
break;
}
}
void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod)
{
VTermState *state = vt->state;
if(col == state->mouse_col && row == state->mouse_row)
return;
state->mouse_col = col;
state->mouse_row = row;
if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) ||
(state->mouse_flags & MOUSE_WANT_MOVE)) {
int button = state->mouse_buttons & 0x01 ? 1 :
state->mouse_buttons & 0x02 ? 2 :
state->mouse_buttons & 0x04 ? 3 : 4;
output_mouse(state, button-1 + 0x20, 1, mod, col, row);
}
}
void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod)
{
VTermState *state = vt->state;
int old_buttons = state->mouse_buttons;
if(button > 0 && button <= 3) {
if(pressed)
state->mouse_buttons |= (1 << (button-1));
else
state->mouse_buttons &= ~(1 << (button-1));
}
/* Most of the time we don't get button releases from 4/5 */
if(state->mouse_buttons == old_buttons && button < 4)
return;
if(button < 4) {
output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row);
}
else if(button < 6) {
output_mouse(state, button-4 + 0x40, pressed, mod, state->mouse_col, state->mouse_row);
}
}

346
src/libvterm/src/parser.c Normal file
View File

@@ -0,0 +1,346 @@
#include "vterm_internal.h"
#include <stdio.h>
#include <string.h>
#define CSI_ARGS_MAX 16
#define CSI_LEADER_MAX 16
#define CSI_INTERMED_MAX 16
static void do_control(VTerm *vt, unsigned char control)
{
if(vt->parser_callbacks && vt->parser_callbacks->control)
if((*vt->parser_callbacks->control)(control, vt->cbdata))
return;
DEBUG_LOG1("libvterm: Unhandled control 0x%02x\n", control);
}
static void do_string_csi(VTerm *vt, const char *args, size_t arglen, char command)
{
int i = 0;
int leaderlen = 0;
char leader[CSI_LEADER_MAX];
int argcount = 1; /* Always at least 1 arg */
long csi_args[CSI_ARGS_MAX];
int argi;
int intermedlen = 0;
char intermed[CSI_INTERMED_MAX];
/* Extract leader bytes 0x3c to 0x3f */
for( ; i < (int)arglen; i++) {
if(args[i] < 0x3c || args[i] > 0x3f)
break;
if(leaderlen < CSI_LEADER_MAX-1)
leader[leaderlen++] = args[i];
}
leader[leaderlen] = 0;
for( ; i < (int)arglen; i++)
if(args[i] == 0x3b || args[i] == 0x3a) /* ; or : */
argcount++;
/* TODO: Consider if these buffers should live in the VTerm struct itself */
if(argcount > CSI_ARGS_MAX)
argcount = CSI_ARGS_MAX;
for(argi = 0; argi < argcount; argi++)
csi_args[argi] = CSI_ARG_MISSING;
argi = 0;
for(i = leaderlen; i < (int)arglen && argi < argcount; i++) {
switch(args[i]) {
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
if(csi_args[argi] == CSI_ARG_MISSING)
csi_args[argi] = 0;
csi_args[argi] *= 10;
csi_args[argi] += args[i] - '0';
break;
case 0x3a:
csi_args[argi] |= CSI_ARG_FLAG_MORE;
/* FALLTHROUGH */
case 0x3b:
argi++;
break;
default:
goto done_leader;
}
}
done_leader: ;
for( ; i < (int)arglen; i++) {
if((args[i] & 0xf0) != 0x20)
break;
if(intermedlen < CSI_INTERMED_MAX-1)
intermed[intermedlen++] = args[i];
}
intermed[intermedlen] = 0;
if(i < (int)arglen) {
DEBUG_LOG2("libvterm: TODO unhandled CSI bytes \"%.*s\"\n", (int)(arglen - i), args + i);
}
#if 0
printf("Parsed CSI args %.*s as:\n", arglen, args);
printf(" leader: %s\n", leader);
for(argi = 0; argi < argcount; argi++) {
printf(" %lu", CSI_ARG(csi_args[argi]));
if(!CSI_ARG_HAS_MORE(csi_args[argi]))
printf("\n");
printf(" intermed: %s\n", intermed);
}
#endif
if(vt->parser_callbacks && vt->parser_callbacks->csi)
if((*vt->parser_callbacks->csi)(leaderlen ? leader : NULL, csi_args, argcount, intermedlen ? intermed : NULL, command, vt->cbdata))
return;
DEBUG_LOG3("libvterm: Unhandled CSI %.*s %c\n", (int)arglen, args, command);
}
static void append_strbuffer(VTerm *vt, const char *str, size_t len)
{
if(len > vt->strbuffer_len - vt->strbuffer_cur) {
len = vt->strbuffer_len - vt->strbuffer_cur;
DEBUG_LOG1("Truncating strbuffer preserve to %zd bytes\n", len);
}
if(len > 0) {
strncpy(vt->strbuffer + vt->strbuffer_cur, str, len);
vt->strbuffer_cur += len;
}
}
static size_t do_string(VTerm *vt, const char *str_frag, size_t len)
{
size_t eaten;
if(vt->strbuffer_cur) {
if(str_frag)
append_strbuffer(vt, str_frag, len);
str_frag = vt->strbuffer;
len = vt->strbuffer_cur;
}
else if(!str_frag) {
DEBUG_LOG("parser.c: TODO: No strbuffer _and_ no final fragment???\n");
len = 0;
}
vt->strbuffer_cur = 0;
switch(vt->parser_state) {
case NORMAL:
if(vt->parser_callbacks && vt->parser_callbacks->text)
if((eaten = (*vt->parser_callbacks->text)(str_frag, len, vt->cbdata)))
return eaten;
DEBUG_LOG1("libvterm: Unhandled text (%zu chars)\n", len);
return 0;
case ESC:
if(len == 1 && str_frag[0] >= 0x40 && str_frag[0] < 0x60) {
/* C1 emulations using 7bit clean */
/* ESC 0x40 == 0x80 */
do_control(vt, str_frag[0] + 0x40);
return 0;
}
if(vt->parser_callbacks && vt->parser_callbacks->escape)
if((*vt->parser_callbacks->escape)(str_frag, len, vt->cbdata))
return 0;
DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", str_frag[len-1]);
return 0;
case CSI:
do_string_csi(vt, str_frag, len - 1, str_frag[len - 1]);
return 0;
case OSC:
if(vt->parser_callbacks && vt->parser_callbacks->osc)
if((*vt->parser_callbacks->osc)(str_frag, len, vt->cbdata))
return 0;
DEBUG_LOG2("libvterm: Unhandled OSC %.*s\n", (int)len, str_frag);
return 0;
case DCS:
if(vt->parser_callbacks && vt->parser_callbacks->dcs)
if((*vt->parser_callbacks->dcs)(str_frag, len, vt->cbdata))
return 0;
DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)len, str_frag);
return 0;
case ESC_IN_OSC:
case ESC_IN_DCS:
DEBUG_LOG("libvterm: ARGH! Should never do_string() in ESC_IN_{OSC,DCS}\n");
return 0;
}
return 0;
}
size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
{
size_t pos = 0;
const char *string_start;
switch(vt->parser_state) {
case NORMAL:
string_start = NULL;
break;
case ESC:
case ESC_IN_OSC:
case ESC_IN_DCS:
case CSI:
case OSC:
case DCS:
string_start = bytes;
break;
}
#define ENTER_STRING_STATE(st) do { vt->parser_state = st; string_start = bytes + pos + 1; } while(0)
#define ENTER_NORMAL_STATE() do { vt->parser_state = NORMAL; string_start = NULL; } while(0)
for( ; pos < len; pos++) {
unsigned char c = bytes[pos];
if(c == 0x00 || c == 0x7f) { /* NUL, DEL */
if(vt->parser_state != NORMAL) {
append_strbuffer(vt, string_start, bytes + pos - string_start);
string_start = bytes + pos + 1;
}
continue;
}
if(c == 0x18 || c == 0x1a) { /* CAN, SUB */
ENTER_NORMAL_STATE();
continue;
}
else if(c == 0x1b) { /* ESC */
if(vt->parser_state == OSC)
vt->parser_state = ESC_IN_OSC;
else if(vt->parser_state == DCS)
vt->parser_state = ESC_IN_DCS;
else
ENTER_STRING_STATE(ESC);
continue;
}
else if(c == 0x07 && /* BEL, can stand for ST in OSC or DCS state */
(vt->parser_state == OSC || vt->parser_state == DCS)) {
/* fallthrough */
}
else if(c < 0x20) { /* other C0 */
if(vt->parser_state != NORMAL)
append_strbuffer(vt, string_start, bytes + pos - string_start);
do_control(vt, c);
if(vt->parser_state != NORMAL)
string_start = bytes + pos + 1;
continue;
}
/* else fallthrough */
switch(vt->parser_state) {
case ESC_IN_OSC:
case ESC_IN_DCS:
if(c == 0x5c) { /* ST */
switch(vt->parser_state) {
case ESC_IN_OSC: vt->parser_state = OSC; break;
case ESC_IN_DCS: vt->parser_state = DCS; break;
default: break;
}
do_string(vt, string_start, bytes + pos - string_start - 1);
ENTER_NORMAL_STATE();
break;
}
vt->parser_state = ESC;
string_start = bytes + pos;
/* else fallthrough */
case ESC:
switch(c) {
case 0x50: /* DCS */
ENTER_STRING_STATE(DCS);
break;
case 0x5b: /* CSI */
ENTER_STRING_STATE(CSI);
break;
case 0x5d: /* OSC */
ENTER_STRING_STATE(OSC);
break;
default:
if(c >= 0x30 && c < 0x7f) {
/* +1 to pos because we want to include this command byte as well */
do_string(vt, string_start, bytes + pos - string_start + 1);
ENTER_NORMAL_STATE();
}
else if(c >= 0x20 && c < 0x30) {
/* intermediate byte */
}
else {
DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c);
}
}
break;
case CSI:
if(c >= 0x40 && c <= 0x7f) {
/* +1 to pos because we want to include this command byte as well */
do_string(vt, string_start, bytes + pos - string_start + 1);
ENTER_NORMAL_STATE();
}
break;
case OSC:
case DCS:
if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) {
do_string(vt, string_start, bytes + pos - string_start);
ENTER_NORMAL_STATE();
}
break;
case NORMAL:
if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) {
switch(c) {
case 0x90: /* DCS */
ENTER_STRING_STATE(DCS);
break;
case 0x9b: /* CSI */
ENTER_STRING_STATE(CSI);
break;
case 0x9d: /* OSC */
ENTER_STRING_STATE(OSC);
break;
default:
do_control(vt, c);
break;
}
}
else {
size_t text_eaten = do_string(vt, bytes + pos, len - pos);
if(text_eaten == 0) {
string_start = bytes + pos;
goto pause;
}
pos += (text_eaten - 1); /* we'll ++ it again in a moment */
}
break;
}
}
pause:
if(string_start && string_start < len + bytes) {
size_t remaining = len - (string_start - bytes);
append_strbuffer(vt, string_start, remaining);
}
return len;
}

504
src/libvterm/src/pen.c Normal file
View File

@@ -0,0 +1,504 @@
#include "vterm_internal.h"
#include <stdio.h>
static const VTermColor ansi_colors[] = {
/* R G B */
{ 0, 0, 0 }, /* black */
{ 224, 0, 0 }, /* red */
{ 0, 224, 0 }, /* green */
{ 224, 224, 0 }, /* yellow */
{ 0, 0, 224 }, /* blue */
{ 224, 0, 224 }, /* magenta */
{ 0, 224, 224 }, /* cyan */
{ 224, 224, 224 }, /* white == light grey */
/* high intensity */
{ 128, 128, 128 }, /* black */
{ 255, 64, 64 }, /* red */
{ 64, 255, 64 }, /* green */
{ 255, 255, 64 }, /* yellow */
{ 64, 64, 255 }, /* blue */
{ 255, 64, 255 }, /* magenta */
{ 64, 255, 255 }, /* cyan */
{ 255, 255, 255 }, /* white for real */
};
static int ramp6[] = {
0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF,
};
static int ramp24[] = {
0x00, 0x0B, 0x16, 0x21, 0x2C, 0x37, 0x42, 0x4D, 0x58, 0x63, 0x6E, 0x79,
0x85, 0x90, 0x9B, 0xA6, 0xB1, 0xBC, 0xC7, 0xD2, 0xDD, 0xE8, 0xF3, 0xFF,
};
static bool lookup_colour_ansi(const VTermState *state, long index, VTermColor *col)
{
if(index >= 0 && index < 16) {
*col = state->colors[index];
return true;
}
return false;
}
static bool lookup_colour_palette(const VTermState *state, long index, VTermColor *col)
{
if(index >= 0 && index < 16) {
/* Normal 8 colours or high intensity - parse as palette 0 */
return lookup_colour_ansi(state, index, col);
}
else if(index >= 16 && index < 232) {
/* 216-colour cube */
index -= 16;
col->blue = ramp6[index % 6];
col->green = ramp6[index/6 % 6];
col->red = ramp6[index/6/6 % 6];
return true;
}
else if(index >= 232 && index < 256) {
/* 24 greyscales */
index -= 232;
col->blue = ramp24[index];
col->green = ramp24[index];
col->red = ramp24[index];
return true;
}
return false;
}
static int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col, int *index)
{
switch(palette) {
case 2: /* RGB mode - 3 args contain colour values directly */
if(argcount < 3)
return argcount;
col->red = CSI_ARG(args[0]);
col->green = CSI_ARG(args[1]);
col->blue = CSI_ARG(args[2]);
return 3;
case 5: /* XTerm 256-colour mode */
if(index)
*index = CSI_ARG_OR(args[0], -1);
lookup_colour_palette(state, argcount ? CSI_ARG_OR(args[0], -1) : -1, col);
return argcount ? 1 : 0;
default:
DEBUG_LOG1("Unrecognised colour palette %d\n", palette);
return 0;
}
}
/* Some conveniences */
static void setpenattr(VTermState *state, VTermAttr attr, VTermValueType type UNUSED, VTermValue *val)
{
#ifdef DEBUG
if(type != vterm_get_attr_type(attr)) {
DEBUG_LOG("Cannot set attr %d as it has type %d, not type %d\n",
attr, vterm_get_attr_type(attr), type);
return;
}
#endif
if(state->callbacks && state->callbacks->setpenattr)
(*state->callbacks->setpenattr)(attr, val, state->cbdata);
}
static void setpenattr_bool(VTermState *state, VTermAttr attr, int boolean)
{
VTermValue val;
val.boolean = boolean;
setpenattr(state, attr, VTERM_VALUETYPE_BOOL, &val);
}
static void setpenattr_int(VTermState *state, VTermAttr attr, int number)
{
VTermValue val;
val.number = number;
setpenattr(state, attr, VTERM_VALUETYPE_INT, &val);
}
static void setpenattr_col(VTermState *state, VTermAttr attr, VTermColor color)
{
VTermValue val;
val.color = color;
setpenattr(state, attr, VTERM_VALUETYPE_COLOR, &val);
}
static void set_pen_col_ansi(VTermState *state, VTermAttr attr, long col)
{
VTermColor *colp = (attr == VTERM_ATTR_BACKGROUND) ? &state->pen.bg : &state->pen.fg;
lookup_colour_ansi(state, col, colp);
setpenattr_col(state, attr, *colp);
}
INTERNAL void vterm_state_newpen(VTermState *state)
{
int col;
/* 90% grey so that pure white is brighter */
state->default_fg.red = state->default_fg.green = state->default_fg.blue = 240;
state->default_bg.red = state->default_bg.green = state->default_bg.blue = 0;
for(col = 0; col < 16; col++)
state->colors[col] = ansi_colors[col];
}
INTERNAL void vterm_state_resetpen(VTermState *state)
{
state->pen.bold = 0; setpenattr_bool(state, VTERM_ATTR_BOLD, 0);
state->pen.underline = 0; setpenattr_int( state, VTERM_ATTR_UNDERLINE, 0);
state->pen.italic = 0; setpenattr_bool(state, VTERM_ATTR_ITALIC, 0);
state->pen.blink = 0; setpenattr_bool(state, VTERM_ATTR_BLINK, 0);
state->pen.reverse = 0; setpenattr_bool(state, VTERM_ATTR_REVERSE, 0);
state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0);
state->pen.font = 0; setpenattr_int( state, VTERM_ATTR_FONT, 0);
state->fg_index = -1;
state->bg_index = -1;
state->pen.fg = state->default_fg; setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->default_fg);
state->pen.bg = state->default_bg; setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->default_bg);
}
INTERNAL void vterm_state_savepen(VTermState *state, int save)
{
if(save) {
state->saved.pen = state->pen;
}
else {
state->pen = state->saved.pen;
setpenattr_bool(state, VTERM_ATTR_BOLD, state->pen.bold);
setpenattr_int( state, VTERM_ATTR_UNDERLINE, state->pen.underline);
setpenattr_bool(state, VTERM_ATTR_ITALIC, state->pen.italic);
setpenattr_bool(state, VTERM_ATTR_BLINK, state->pen.blink);
setpenattr_bool(state, VTERM_ATTR_REVERSE, state->pen.reverse);
setpenattr_bool(state, VTERM_ATTR_STRIKE, state->pen.strike);
setpenattr_int( state, VTERM_ATTR_FONT, state->pen.font);
setpenattr_col( state, VTERM_ATTR_FOREGROUND, state->pen.fg);
setpenattr_col( state, VTERM_ATTR_BACKGROUND, state->pen.bg);
}
}
void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg)
{
*default_fg = state->default_fg;
*default_bg = state->default_bg;
}
void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col)
{
lookup_colour_palette(state, index, col);
}
void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg)
{
state->default_fg = *default_fg;
state->default_bg = *default_bg;
}
void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col)
{
if(index >= 0 && index < 16)
state->colors[index] = *col;
}
void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright)
{
state->bold_is_highbright = bold_is_highbright;
}
INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argcount)
{
/* SGR - ECMA-48 8.3.117 */
int argi = 0;
int value;
while(argi < argcount) {
/* This logic is easier to do 'done' backwards; set it true, and make it
false again in the 'default' case */
int done = 1;
long arg;
switch(arg = CSI_ARG(args[argi])) {
case CSI_ARG_MISSING:
case 0: /* Reset */
vterm_state_resetpen(state);
break;
case 1: /* Bold on */
state->pen.bold = 1;
setpenattr_bool(state, VTERM_ATTR_BOLD, 1);
if(state->fg_index > -1 && state->fg_index < 8 && state->bold_is_highbright)
set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, state->fg_index + (state->pen.bold ? 8 : 0));
break;
case 3: /* Italic on */
state->pen.italic = 1;
setpenattr_bool(state, VTERM_ATTR_ITALIC, 1);
break;
case 4: /* Underline single */
state->pen.underline = 1;
setpenattr_int(state, VTERM_ATTR_UNDERLINE, 1);
break;
case 5: /* Blink */
state->pen.blink = 1;
setpenattr_bool(state, VTERM_ATTR_BLINK, 1);
break;
case 7: /* Reverse on */
state->pen.reverse = 1;
setpenattr_bool(state, VTERM_ATTR_REVERSE, 1);
break;
case 9: /* Strikethrough on */
state->pen.strike = 1;
setpenattr_bool(state, VTERM_ATTR_STRIKE, 1);
break;
case 10: case 11: case 12: case 13: case 14:
case 15: case 16: case 17: case 18: case 19: /* Select font */
state->pen.font = CSI_ARG(args[argi]) - 10;
setpenattr_int(state, VTERM_ATTR_FONT, state->pen.font);
break;
case 21: /* Underline double */
state->pen.underline = 2;
setpenattr_int(state, VTERM_ATTR_UNDERLINE, 2);
break;
case 22: /* Bold off */
state->pen.bold = 0;
setpenattr_bool(state, VTERM_ATTR_BOLD, 0);
break;
case 23: /* Italic and Gothic (currently unsupported) off */
state->pen.italic = 0;
setpenattr_bool(state, VTERM_ATTR_ITALIC, 0);
break;
case 24: /* Underline off */
state->pen.underline = 0;
setpenattr_int(state, VTERM_ATTR_UNDERLINE, 0);
break;
case 25: /* Blink off */
state->pen.blink = 0;
setpenattr_bool(state, VTERM_ATTR_BLINK, 0);
break;
case 27: /* Reverse off */
state->pen.reverse = 0;
setpenattr_bool(state, VTERM_ATTR_REVERSE, 0);
break;
case 29: /* Strikethrough off */
state->pen.strike = 0;
setpenattr_bool(state, VTERM_ATTR_STRIKE, 0);
break;
case 30: case 31: case 32: case 33:
case 34: case 35: case 36: case 37: /* Foreground colour palette */
value = CSI_ARG(args[argi]) - 30;
state->fg_index = value;
if(state->pen.bold && state->bold_is_highbright)
value += 8;
set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value);
break;
case 38: /* Foreground colour alternative palette */
state->fg_index = -1;
if(argcount - argi < 1)
return;
argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg, &state->fg_index);
setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg);
break;
case 39: /* Foreground colour default */
state->fg_index = -1;
state->pen.fg = state->default_fg;
setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg);
break;
case 40: case 41: case 42: case 43:
case 44: case 45: case 46: case 47: /* Background colour palette */
value = CSI_ARG(args[argi]) - 40;
state->bg_index = value;
set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value);
break;
case 48: /* Background colour alternative palette */
state->bg_index = -1;
if(argcount - argi < 1)
return;
argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg, &state->bg_index);
setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg);
break;
case 49: /* Default background */
state->bg_index = -1;
state->pen.bg = state->default_bg;
setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg);
break;
case 90: case 91: case 92: case 93:
case 94: case 95: case 96: case 97: /* Foreground colour high-intensity palette */
value = CSI_ARG(args[argi]) - 90 + 8;
state->fg_index = value;
set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value);
break;
case 100: case 101: case 102: case 103:
case 104: case 105: case 106: case 107: /* Background colour high-intensity palette */
value = CSI_ARG(args[argi]) - 100 + 8;
state->bg_index = value;
set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value);
break;
default:
done = 0;
break;
}
if(!done)
{
DEBUG_LOG1("libvterm: Unhandled CSI SGR %lu\n", arg);
}
while(CSI_ARG_HAS_MORE(args[argi++]));
}
}
INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount UNUSED)
{
int argi = 0;
if(state->pen.bold)
args[argi++] = 1;
if(state->pen.italic)
args[argi++] = 3;
if(state->pen.underline == 1)
args[argi++] = 4;
if(state->pen.blink)
args[argi++] = 5;
if(state->pen.reverse)
args[argi++] = 7;
if(state->pen.strike)
args[argi++] = 9;
if(state->pen.font)
args[argi++] = 10 + state->pen.font;
if(state->pen.underline == 2)
args[argi++] = 21;
if(state->fg_index >= 0 && state->fg_index < 8)
args[argi++] = 30 + state->fg_index;
else if(state->fg_index >= 8 && state->fg_index < 16)
args[argi++] = 90 + state->fg_index - 8;
else if(state->fg_index >= 16 && state->fg_index < 256) {
args[argi++] = CSI_ARG_FLAG_MORE|38;
args[argi++] = CSI_ARG_FLAG_MORE|5;
args[argi++] = state->fg_index;
}
else if(state->fg_index == -1) {
/* Send palette 2 if the actual FG colour is not default */
if(state->pen.fg.red != state->default_fg.red ||
state->pen.fg.green != state->default_fg.green ||
state->pen.fg.blue != state->default_fg.blue ) {
args[argi++] = CSI_ARG_FLAG_MORE|38;
args[argi++] = CSI_ARG_FLAG_MORE|2;
args[argi++] = CSI_ARG_FLAG_MORE | state->pen.fg.red;
args[argi++] = CSI_ARG_FLAG_MORE | state->pen.fg.green;
args[argi++] = state->pen.fg.blue;
}
}
if(state->bg_index >= 0 && state->bg_index < 8)
args[argi++] = 40 + state->bg_index;
else if(state->bg_index >= 8 && state->bg_index < 16)
args[argi++] = 100 + state->bg_index - 8;
else if(state->bg_index >= 16 && state->bg_index < 256) {
args[argi++] = CSI_ARG_FLAG_MORE|48;
args[argi++] = CSI_ARG_FLAG_MORE|5;
args[argi++] = state->bg_index;
}
else if(state->bg_index == -1) {
/* Send palette 2 if the actual BG colour is not default */
if(state->pen.bg.red != state->default_bg.red ||
state->pen.bg.green != state->default_bg.green ||
state->pen.bg.blue != state->default_bg.blue ) {
args[argi++] = CSI_ARG_FLAG_MORE|48;
args[argi++] = CSI_ARG_FLAG_MORE|2;
args[argi++] = CSI_ARG_FLAG_MORE | state->pen.bg.red;
args[argi++] = CSI_ARG_FLAG_MORE | state->pen.bg.green;
args[argi++] = state->pen.bg.blue;
}
}
return argi;
}
int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val)
{
switch(attr) {
case VTERM_ATTR_BOLD:
val->boolean = state->pen.bold;
return 1;
case VTERM_ATTR_UNDERLINE:
val->number = state->pen.underline;
return 1;
case VTERM_ATTR_ITALIC:
val->boolean = state->pen.italic;
return 1;
case VTERM_ATTR_BLINK:
val->boolean = state->pen.blink;
return 1;
case VTERM_ATTR_REVERSE:
val->boolean = state->pen.reverse;
return 1;
case VTERM_ATTR_STRIKE:
val->boolean = state->pen.strike;
return 1;
case VTERM_ATTR_FONT:
val->number = state->pen.font;
return 1;
case VTERM_ATTR_FOREGROUND:
val->color = state->pen.fg;
return 1;
case VTERM_ATTR_BACKGROUND:
val->color = state->pen.bg;
return 1;
}
return 0;
}

56
src/libvterm/src/rect.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* Some utility functions on VTermRect structures
*/
#define STRFrect "(%d,%d-%d,%d)"
#define ARGSrect(r) (r).start_row, (r).start_col, (r).end_row, (r).end_col
/* Expand dst to contain src as well */
static void rect_expand(VTermRect *dst, VTermRect *src)
{
if(dst->start_row > src->start_row) dst->start_row = src->start_row;
if(dst->start_col > src->start_col) dst->start_col = src->start_col;
if(dst->end_row < src->end_row) dst->end_row = src->end_row;
if(dst->end_col < src->end_col) dst->end_col = src->end_col;
}
/* Clip the dst to ensure it does not step outside of bounds */
static void rect_clip(VTermRect *dst, VTermRect *bounds)
{
if(dst->start_row < bounds->start_row) dst->start_row = bounds->start_row;
if(dst->start_col < bounds->start_col) dst->start_col = bounds->start_col;
if(dst->end_row > bounds->end_row) dst->end_row = bounds->end_row;
if(dst->end_col > bounds->end_col) dst->end_col = bounds->end_col;
/* Ensure it doesn't end up negatively-sized */
if(dst->end_row < dst->start_row) dst->end_row = dst->start_row;
if(dst->end_col < dst->start_col) dst->end_col = dst->start_col;
}
/* True if the two rectangles are equal */
static int rect_equal(VTermRect *a, VTermRect *b)
{
return (a->start_row == b->start_row) &&
(a->start_col == b->start_col) &&
(a->end_row == b->end_row) &&
(a->end_col == b->end_col);
}
/* True if small is contained entirely within big */
static int rect_contains(VTermRect *big, VTermRect *small)
{
if(small->start_row < big->start_row) return 0;
if(small->start_col < big->start_col) return 0;
if(small->end_row > big->end_row) return 0;
if(small->end_col > big->end_col) return 0;
return 1;
}
/* True if the rectangles overlap at all */
static int rect_intersects(VTermRect *a, VTermRect *b)
{
if(a->start_row > b->end_row || b->start_row > a->end_row)
return 0;
if(a->start_col > b->end_col || b->start_col > a->end_col)
return 0;
return 1;
}

937
src/libvterm/src/screen.c Normal file
View File

@@ -0,0 +1,937 @@
#include "vterm_internal.h"
#include <stdio.h>
#include <string.h>
#include "rect.h"
#include "utf8.h"
#define UNICODE_SPACE 0x20
#define UNICODE_LINEFEED 0x0a
/* State of the pen at some moment in time, also used in a cell */
typedef struct
{
/* After the bitfield */
VTermColor fg, bg;
unsigned int bold : 1;
unsigned int underline : 2;
unsigned int italic : 1;
unsigned int blink : 1;
unsigned int reverse : 1;
unsigned int strike : 1;
unsigned int font : 4; /* 0 to 9 */
/* Extra state storage that isn't strictly pen-related */
unsigned int protected_cell : 1;
unsigned int dwl : 1; /* on a DECDWL or DECDHL line */
unsigned int dhl : 2; /* on a DECDHL line (1=top 2=bottom) */
} ScreenPen;
/* Internal representation of a screen cell */
typedef struct
{
uint32_t chars[VTERM_MAX_CHARS_PER_CELL];
ScreenPen pen;
} ScreenCell;
static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell);
struct VTermScreen
{
VTerm *vt;
VTermState *state;
const VTermScreenCallbacks *callbacks;
void *cbdata;
VTermDamageSize damage_merge;
/* start_row == -1 => no damage */
VTermRect damaged;
VTermRect pending_scrollrect;
int pending_scroll_downward, pending_scroll_rightward;
int rows;
int cols;
int global_reverse;
/* Primary and Altscreen. buffers[1] is lazily allocated as needed */
ScreenCell *buffers[2];
/* buffer will == buffers[0] or buffers[1], depending on altscreen */
ScreenCell *buffer;
/* buffer for a single screen row used in scrollback storage callbacks */
VTermScreenCell *sb_buffer;
ScreenPen pen;
};
static ScreenCell *getcell(const VTermScreen *screen, int row, int col)
{
if(row < 0 || row >= screen->rows)
return NULL;
if(col < 0 || col >= screen->cols)
return NULL;
return screen->buffer + (screen->cols * row) + col;
}
static ScreenCell *realloc_buffer(VTermScreen *screen, ScreenCell *buffer, int new_rows, int new_cols)
{
ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols);
int row, col;
for(row = 0; row < new_rows; row++) {
for(col = 0; col < new_cols; col++) {
ScreenCell *new_cell = new_buffer + row*new_cols + col;
if(buffer && row < screen->rows && col < screen->cols)
*new_cell = buffer[row * screen->cols + col];
else {
new_cell->chars[0] = 0;
new_cell->pen = screen->pen;
}
}
}
if(buffer)
vterm_allocator_free(screen->vt, buffer);
return new_buffer;
}
static void damagerect(VTermScreen *screen, VTermRect rect)
{
VTermRect emit;
switch(screen->damage_merge) {
case VTERM_DAMAGE_CELL:
/* Always emit damage event */
emit = rect;
break;
case VTERM_DAMAGE_ROW:
/* Emit damage longer than one row. Try to merge with existing damage in
* the same row */
if(rect.end_row > rect.start_row + 1) {
/* Bigger than 1 line - flush existing, emit this */
vterm_screen_flush_damage(screen);
emit = rect;
}
else if(screen->damaged.start_row == -1) {
/* None stored yet */
screen->damaged = rect;
return;
}
else if(rect.start_row == screen->damaged.start_row) {
/* Merge with the stored line */
if(screen->damaged.start_col > rect.start_col)
screen->damaged.start_col = rect.start_col;
if(screen->damaged.end_col < rect.end_col)
screen->damaged.end_col = rect.end_col;
return;
}
else {
/* Emit the currently stored line, store a new one */
emit = screen->damaged;
screen->damaged = rect;
}
break;
case VTERM_DAMAGE_SCREEN:
case VTERM_DAMAGE_SCROLL:
/* Never emit damage event */
if(screen->damaged.start_row == -1)
screen->damaged = rect;
else {
rect_expand(&screen->damaged, &rect);
}
return;
default:
DEBUG_LOG1("TODO: Maybe merge damage for level %d\n", screen->damage_merge);
return;
}
if(screen->callbacks && screen->callbacks->damage)
(*screen->callbacks->damage)(emit, screen->cbdata);
}
static void damagescreen(VTermScreen *screen)
{
VTermRect rect = {0,0,0,0};
rect.end_row = screen->rows;
rect.end_col = screen->cols;
damagerect(screen, rect);
}
static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
{
int i;
int col;
VTermRect rect;
VTermScreen *screen = user;
ScreenCell *cell = getcell(screen, pos.row, pos.col);
if(!cell)
return 0;
for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) {
cell->chars[i] = info->chars[i];
cell->pen = screen->pen;
}
if(i < VTERM_MAX_CHARS_PER_CELL)
cell->chars[i] = 0;
for(col = 1; col < info->width; col++)
getcell(screen, pos.row, pos.col + col)->chars[0] = (uint32_t)-1;
rect.start_row = pos.row;
rect.end_row = pos.row+1;
rect.start_col = pos.col;
rect.end_col = pos.col+info->width;
cell->pen.protected_cell = info->protected_cell;
cell->pen.dwl = info->dwl;
cell->pen.dhl = info->dhl;
damagerect(screen, rect);
return 1;
}
static int moverect_internal(VTermRect dest, VTermRect src, void *user)
{
VTermScreen *screen = user;
if(screen->callbacks && screen->callbacks->sb_pushline &&
dest.start_row == 0 && dest.start_col == 0 && /* starts top-left corner */
dest.end_col == screen->cols && /* full width */
screen->buffer == screen->buffers[0]) { /* not altscreen */
VTermPos pos;
for(pos.row = 0; pos.row < src.start_row; pos.row++) {
for(pos.col = 0; pos.col < screen->cols; pos.col++)
vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col);
(screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata);
}
}
{
int cols = src.end_col - src.start_col;
int downward = src.start_row - dest.start_row;
int init_row, test_row, inc_row;
int row;
if(downward < 0) {
init_row = dest.end_row - 1;
test_row = dest.start_row - 1;
inc_row = -1;
}
else {
init_row = dest.start_row;
test_row = dest.end_row;
inc_row = +1;
}
for(row = init_row; row != test_row; row += inc_row)
memmove(getcell(screen, row, dest.start_col),
getcell(screen, row + downward, src.start_col),
cols * sizeof(ScreenCell));
}
return 1;
}
static int moverect_user(VTermRect dest, VTermRect src, void *user)
{
VTermScreen *screen = user;
if(screen->callbacks && screen->callbacks->moverect) {
if(screen->damage_merge != VTERM_DAMAGE_SCROLL)
/* Avoid an infinite loop */
vterm_screen_flush_damage(screen);
if((*screen->callbacks->moverect)(dest, src, screen->cbdata))
return 1;
}
damagerect(screen, dest);
return 1;
}
static int erase_internal(VTermRect rect, int selective, void *user)
{
VTermScreen *screen = user;
int row, col;
for(row = rect.start_row; row < screen->state->rows && row < rect.end_row; row++) {
const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row);
for(col = rect.start_col; col < rect.end_col; col++) {
ScreenCell *cell = getcell(screen, row, col);
if(selective && cell->pen.protected_cell)
continue;
cell->chars[0] = 0;
cell->pen = screen->pen;
cell->pen.dwl = info->doublewidth;
cell->pen.dhl = info->doubleheight;
}
}
return 1;
}
static int erase_user(VTermRect rect, int selective UNUSED, void *user)
{
VTermScreen *screen = user;
damagerect(screen, rect);
return 1;
}
static int erase(VTermRect rect, int selective, void *user)
{
erase_internal(rect, selective, user);
return erase_user(rect, 0, user);
}
static int scrollrect(VTermRect rect, int downward, int rightward, void *user)
{
VTermScreen *screen = user;
if(screen->damage_merge != VTERM_DAMAGE_SCROLL) {
vterm_scroll_rect(rect, downward, rightward,
moverect_internal, erase_internal, screen);
vterm_screen_flush_damage(screen);
vterm_scroll_rect(rect, downward, rightward,
moverect_user, erase_user, screen);
return 1;
}
if(screen->damaged.start_row != -1 &&
!rect_intersects(&rect, &screen->damaged)) {
vterm_screen_flush_damage(screen);
}
if(screen->pending_scrollrect.start_row == -1) {
screen->pending_scrollrect = rect;
screen->pending_scroll_downward = downward;
screen->pending_scroll_rightward = rightward;
}
else if(rect_equal(&screen->pending_scrollrect, &rect) &&
((screen->pending_scroll_downward == 0 && downward == 0) ||
(screen->pending_scroll_rightward == 0 && rightward == 0))) {
screen->pending_scroll_downward += downward;
screen->pending_scroll_rightward += rightward;
}
else {
vterm_screen_flush_damage(screen);
screen->pending_scrollrect = rect;
screen->pending_scroll_downward = downward;
screen->pending_scroll_rightward = rightward;
}
vterm_scroll_rect(rect, downward, rightward,
moverect_internal, erase_internal, screen);
if(screen->damaged.start_row == -1)
return 1;
if(rect_contains(&rect, &screen->damaged)) {
/* Scroll region entirely contains the damage; just move it */
vterm_rect_move(&screen->damaged, -downward, -rightward);
rect_clip(&screen->damaged, &rect);
}
/* There are a number of possible cases here, but lets restrict this to only
* the common case where we might actually gain some performance by
* optimising it. Namely, a vertical scroll that neatly cuts the damage
* region in half.
*/
else if(rect.start_col <= screen->damaged.start_col &&
rect.end_col >= screen->damaged.end_col &&
rightward == 0) {
if(screen->damaged.start_row >= rect.start_row &&
screen->damaged.start_row < rect.end_row) {
screen->damaged.start_row -= downward;
if(screen->damaged.start_row < rect.start_row)
screen->damaged.start_row = rect.start_row;
if(screen->damaged.start_row > rect.end_row)
screen->damaged.start_row = rect.end_row;
}
if(screen->damaged.end_row >= rect.start_row &&
screen->damaged.end_row < rect.end_row) {
screen->damaged.end_row -= downward;
if(screen->damaged.end_row < rect.start_row)
screen->damaged.end_row = rect.start_row;
if(screen->damaged.end_row > rect.end_row)
screen->damaged.end_row = rect.end_row;
}
}
else {
DEBUG_LOG2("TODO: Just flush and redo damaged=" STRFrect " rect=" STRFrect "\n",
ARGSrect(screen->damaged), ARGSrect(rect));
}
return 1;
}
static int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
{
VTermScreen *screen = user;
if(screen->callbacks && screen->callbacks->movecursor)
return (*screen->callbacks->movecursor)(pos, oldpos, visible, screen->cbdata);
return 0;
}
static int setpenattr(VTermAttr attr, VTermValue *val, void *user)
{
VTermScreen *screen = user;
switch(attr) {
case VTERM_ATTR_BOLD:
screen->pen.bold = val->boolean;
return 1;
case VTERM_ATTR_UNDERLINE:
screen->pen.underline = val->number;
return 1;
case VTERM_ATTR_ITALIC:
screen->pen.italic = val->boolean;
return 1;
case VTERM_ATTR_BLINK:
screen->pen.blink = val->boolean;
return 1;
case VTERM_ATTR_REVERSE:
screen->pen.reverse = val->boolean;
return 1;
case VTERM_ATTR_STRIKE:
screen->pen.strike = val->boolean;
return 1;
case VTERM_ATTR_FONT:
screen->pen.font = val->number;
return 1;
case VTERM_ATTR_FOREGROUND:
screen->pen.fg = val->color;
return 1;
case VTERM_ATTR_BACKGROUND:
screen->pen.bg = val->color;
return 1;
}
return 0;
}
static int settermprop(VTermProp prop, VTermValue *val, void *user)
{
VTermScreen *screen = user;
switch(prop) {
case VTERM_PROP_ALTSCREEN:
if(val->boolean && !screen->buffers[1])
return 0;
screen->buffer = val->boolean ? screen->buffers[1] : screen->buffers[0];
/* only send a damage event on disable; because during enable there's an
* erase that sends a damage anyway
*/
if(!val->boolean)
damagescreen(screen);
break;
case VTERM_PROP_REVERSE:
screen->global_reverse = val->boolean;
damagescreen(screen);
break;
default:
; /* ignore */
}
if(screen->callbacks && screen->callbacks->settermprop)
return (*screen->callbacks->settermprop)(prop, val, screen->cbdata);
return 1;
}
static int bell(void *user)
{
VTermScreen *screen = user;
if(screen->callbacks && screen->callbacks->bell)
return (*screen->callbacks->bell)(screen->cbdata);
return 0;
}
static int resize(int new_rows, int new_cols, VTermPos *delta, void *user)
{
VTermScreen *screen = user;
int is_altscreen = (screen->buffers[1] && screen->buffer == screen->buffers[1]);
int old_rows = screen->rows;
int old_cols = screen->cols;
int first_blank_row;
if(!is_altscreen && new_rows < old_rows) {
/* Fewer rows - determine if we're going to scroll at all, and if so, push
those lines to scrollback */
VTermPos pos = { 0, 0 };
VTermPos cursor = screen->state->pos;
/* Find the first blank row after the cursor. */
for(pos.row = old_rows - 1; pos.row >= new_rows; pos.row--)
if(!vterm_screen_is_eol(screen, pos) || cursor.row == pos.row)
break;
first_blank_row = pos.row + 1;
if(first_blank_row > new_rows) {
VTermRect rect = {0,0,0,0};
rect.end_row = old_rows;
rect.end_col = old_cols;
scrollrect(rect, first_blank_row - new_rows, 0, user);
vterm_screen_flush_damage(screen);
delta->row -= first_blank_row - new_rows;
}
}
screen->buffers[0] = realloc_buffer(screen, screen->buffers[0], new_rows, new_cols);
if(screen->buffers[1])
screen->buffers[1] = realloc_buffer(screen, screen->buffers[1], new_rows, new_cols);
screen->buffer = is_altscreen ? screen->buffers[1] : screen->buffers[0];
screen->rows = new_rows;
screen->cols = new_cols;
if(screen->sb_buffer)
vterm_allocator_free(screen->vt, screen->sb_buffer);
screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols);
if(new_cols > old_cols) {
VTermRect rect;
rect.start_row = 0;
rect.end_row = old_rows;
rect.start_col = old_cols;
rect.end_col = new_cols;
damagerect(screen, rect);
}
if(new_rows > old_rows) {
if(!is_altscreen && screen->callbacks && screen->callbacks->sb_popline) {
int rows = new_rows - old_rows;
while(rows) {
VTermRect rect = {0,0,0,0};
VTermPos pos = { 0, 0 };
if(!(screen->callbacks->sb_popline(screen->cols, screen->sb_buffer, screen->cbdata)))
break;
rect.end_row = screen->rows;
rect.end_col = screen->cols;
scrollrect(rect, -1, 0, user);
for(pos.col = 0; pos.col < screen->cols; pos.col += screen->sb_buffer[pos.col].width)
vterm_screen_set_cell(screen, pos, screen->sb_buffer + pos.col);
rect.end_row = 1;
damagerect(screen, rect);
vterm_screen_flush_damage(screen);
rows--;
delta->row++;
}
}
{
VTermRect rect;
rect.start_row = old_rows;
rect.end_row = new_rows;
rect.start_col = 0;
rect.end_col = new_cols;
damagerect(screen, rect);
}
}
if(screen->callbacks && screen->callbacks->resize)
return (*screen->callbacks->resize)(new_rows, new_cols, screen->cbdata);
return 1;
}
static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user)
{
VTermScreen *screen = user;
int col;
VTermRect rect;
if(newinfo->doublewidth != oldinfo->doublewidth ||
newinfo->doubleheight != oldinfo->doubleheight) {
for(col = 0; col < screen->cols; col++) {
ScreenCell *cell = getcell(screen, row, col);
cell->pen.dwl = newinfo->doublewidth;
cell->pen.dhl = newinfo->doubleheight;
}
rect.start_row = row;
rect.end_row = row + 1;
rect.start_col = 0;
rect.end_col = newinfo->doublewidth ? screen->cols / 2 : screen->cols;
damagerect(screen, rect);
if(newinfo->doublewidth) {
rect.start_col = screen->cols / 2;
rect.end_col = screen->cols;
erase_internal(rect, 0, user);
}
}
return 1;
}
static VTermStateCallbacks state_cbs = {
&putglyph, /* putglyph */
&movecursor, /* movecursor */
&scrollrect, /* scrollrect */
NULL, /* moverect */
&erase, /* erase */
NULL, /* initpen */
&setpenattr, /* setpenattr */
&settermprop, /* settermprop */
&bell, /* bell */
&resize, /* resize */
&setlineinfo /* setlineinfo */
};
static VTermScreen *screen_new(VTerm *vt)
{
VTermState *state = vterm_obtain_state(vt);
VTermScreen *screen;
int rows, cols;
if(!state)
return NULL;
screen = vterm_allocator_malloc(vt, sizeof(VTermScreen));
vterm_get_size(vt, &rows, &cols);
screen->vt = vt;
screen->state = state;
screen->damage_merge = VTERM_DAMAGE_CELL;
screen->damaged.start_row = -1;
screen->pending_scrollrect.start_row = -1;
screen->rows = rows;
screen->cols = cols;
screen->callbacks = NULL;
screen->cbdata = NULL;
screen->buffers[0] = realloc_buffer(screen, NULL, rows, cols);
screen->buffer = screen->buffers[0];
screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols);
vterm_state_set_callbacks(screen->state, &state_cbs, screen);
return screen;
}
INTERNAL void vterm_screen_free(VTermScreen *screen)
{
vterm_allocator_free(screen->vt, screen->buffers[0]);
if(screen->buffers[1])
vterm_allocator_free(screen->vt, screen->buffers[1]);
vterm_allocator_free(screen->vt, screen->sb_buffer);
vterm_allocator_free(screen->vt, screen);
}
void vterm_screen_reset(VTermScreen *screen, int hard)
{
screen->damaged.start_row = -1;
screen->pending_scrollrect.start_row = -1;
vterm_state_reset(screen->state, hard);
vterm_screen_flush_damage(screen);
}
static size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer, size_t len, const VTermRect rect)
{
size_t outpos = 0;
int padding = 0;
int row, col;
#define PUT(c) \
if(utf8) { \
size_t thislen = utf8_seqlen(c); \
if(buffer && outpos + thislen <= len) \
outpos += fill_utf8((c), (char *)buffer + outpos); \
else \
outpos += thislen; \
} \
else { \
if(buffer && outpos + 1 <= len) \
((uint32_t*)buffer)[outpos++] = (c); \
else \
outpos++; \
}
for(row = rect.start_row; row < rect.end_row; row++) {
for(col = rect.start_col; col < rect.end_col; col++) {
ScreenCell *cell = getcell(screen, row, col);
int i;
if(cell->chars[0] == 0)
/* Erased cell, might need a space */
padding++;
else if(cell->chars[0] == (uint32_t)-1)
/* Gap behind a double-width char, do nothing */
;
else {
while(padding) {
PUT(UNICODE_SPACE);
padding--;
}
for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) {
PUT(cell->chars[i]);
}
}
}
if(row < rect.end_row - 1) {
PUT(UNICODE_LINEFEED);
padding = 0;
}
}
return outpos;
}
size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect)
{
return _get_chars(screen, 0, chars, len, rect);
}
size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect)
{
return _get_chars(screen, 1, str, len, rect);
}
/* Copy internal to external representation of a screen cell */
int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell)
{
ScreenCell *intcell = getcell(screen, pos.row, pos.col);
int i;
if(!intcell)
return 0;
for(i = 0; ; i++) {
cell->chars[i] = intcell->chars[i];
if(!intcell->chars[i])
break;
}
cell->attrs.bold = intcell->pen.bold;
cell->attrs.underline = intcell->pen.underline;
cell->attrs.italic = intcell->pen.italic;
cell->attrs.blink = intcell->pen.blink;
cell->attrs.reverse = intcell->pen.reverse ^ screen->global_reverse;
cell->attrs.strike = intcell->pen.strike;
cell->attrs.font = intcell->pen.font;
cell->attrs.dwl = intcell->pen.dwl;
cell->attrs.dhl = intcell->pen.dhl;
cell->fg = intcell->pen.fg;
cell->bg = intcell->pen.bg;
if(pos.col < (screen->cols - 1) &&
getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1)
cell->width = 2;
else
cell->width = 1;
return 1;
}
/* Copy external to internal representation of a screen cell */
/* static because it's only used internally for sb_popline during resize */
static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell)
{
ScreenCell *intcell = getcell(screen, pos.row, pos.col);
int i;
if(!intcell)
return 0;
for(i = 0; ; i++) {
intcell->chars[i] = cell->chars[i];
if(!cell->chars[i])
break;
}
intcell->pen.bold = cell->attrs.bold;
intcell->pen.underline = cell->attrs.underline;
intcell->pen.italic = cell->attrs.italic;
intcell->pen.blink = cell->attrs.blink;
intcell->pen.reverse = cell->attrs.reverse ^ screen->global_reverse;
intcell->pen.strike = cell->attrs.strike;
intcell->pen.font = cell->attrs.font;
intcell->pen.fg = cell->fg;
intcell->pen.bg = cell->bg;
if(cell->width == 2)
getcell(screen, pos.row, pos.col + 1)->chars[0] = (uint32_t)-1;
return 1;
}
int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos)
{
/* This cell is EOL if this and every cell to the right is black */
for(; pos.col < screen->cols; pos.col++) {
ScreenCell *cell = getcell(screen, pos.row, pos.col);
if(cell->chars[0] != 0)
return 0;
}
return 1;
}
VTermScreen *vterm_obtain_screen(VTerm *vt)
{
VTermScreen *screen;
if(vt->screen)
return vt->screen;
screen = screen_new(vt);
vt->screen = screen;
return screen;
}
void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen)
{
if(!screen->buffers[1] && altscreen) {
int rows, cols;
vterm_get_size(screen->vt, &rows, &cols);
screen->buffers[1] = realloc_buffer(screen, NULL, rows, cols);
}
}
void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user)
{
screen->callbacks = callbacks;
screen->cbdata = user;
}
void *vterm_screen_get_cbdata(VTermScreen *screen)
{
return screen->cbdata;
}
void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user)
{
vterm_state_set_unrecognised_fallbacks(screen->state, fallbacks, user);
}
void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen)
{
return vterm_state_get_unrecognised_fbdata(screen->state);
}
void vterm_screen_flush_damage(VTermScreen *screen)
{
if(screen->pending_scrollrect.start_row != -1) {
vterm_scroll_rect(screen->pending_scrollrect, screen->pending_scroll_downward, screen->pending_scroll_rightward,
moverect_user, erase_user, screen);
screen->pending_scrollrect.start_row = -1;
}
if(screen->damaged.start_row != -1) {
if(screen->callbacks && screen->callbacks->damage)
(*screen->callbacks->damage)(screen->damaged, screen->cbdata);
screen->damaged.start_row = -1;
}
}
void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size)
{
vterm_screen_flush_damage(screen);
screen->damage_merge = size;
}
static int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b)
{
if((attrs & VTERM_ATTR_BOLD_MASK) && (a->pen.bold != b->pen.bold))
return 1;
if((attrs & VTERM_ATTR_UNDERLINE_MASK) && (a->pen.underline != b->pen.underline))
return 1;
if((attrs & VTERM_ATTR_ITALIC_MASK) && (a->pen.italic != b->pen.italic))
return 1;
if((attrs & VTERM_ATTR_BLINK_MASK) && (a->pen.blink != b->pen.blink))
return 1;
if((attrs & VTERM_ATTR_REVERSE_MASK) && (a->pen.reverse != b->pen.reverse))
return 1;
if((attrs & VTERM_ATTR_STRIKE_MASK) && (a->pen.strike != b->pen.strike))
return 1;
if((attrs & VTERM_ATTR_FONT_MASK) && (a->pen.font != b->pen.font))
return 1;
if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_equal(a->pen.fg, b->pen.fg))
return 1;
if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_equal(a->pen.bg, b->pen.bg))
return 1;
return 0;
}
int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs)
{
int col;
ScreenCell *target = getcell(screen, pos.row, pos.col);
/* TODO: bounds check */
extent->start_row = pos.row;
extent->end_row = pos.row + 1;
if(extent->start_col < 0)
extent->start_col = 0;
if(extent->end_col < 0)
extent->end_col = screen->cols;
for(col = pos.col - 1; col >= extent->start_col; col--)
if(attrs_differ(attrs, target, getcell(screen, pos.row, col)))
break;
extent->start_col = col + 1;
for(col = pos.col + 1; col < extent->end_col; col++)
if(attrs_differ(attrs, target, getcell(screen, pos.row, col)))
break;
extent->end_col = col - 1;
return 1;
}

1851
src/libvterm/src/state.c Normal file

File diff suppressed because it is too large Load Diff

331
src/libvterm/src/unicode.c Normal file
View File

@@ -0,0 +1,331 @@
#include "vterm_internal.h"
/* ### The following from http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
* With modifications:
* made functions static
* moved 'combining' table to file scope, so other functions can see it
* ###################################################################
*/
/*
* This is an implementation of wcwidth() and wcswidth() (defined in
* IEEE Std 1002.1-2001) for Unicode.
*
* http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
* http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
*
* In fixed-width output devices, Latin characters all occupy a single
* "cell" position of equal width, whereas ideographic CJK characters
* occupy two such cells. Interoperability between terminal-line
* applications and (teletype-style) character terminals using the
* UTF-8 encoding requires agreement on which character should advance
* the cursor by how many cell positions. No established formal
* standards exist at present on which Unicode character shall occupy
* how many cell positions on character terminals. These routines are
* a first attempt of defining such behavior based on simple rules
* applied to data provided by the Unicode Consortium.
*
* For some graphical characters, the Unicode standard explicitly
* defines a character-cell width via the definition of the East Asian
* FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
* In all these cases, there is no ambiguity about which width a
* terminal shall use. For characters in the East Asian Ambiguous (A)
* class, the width choice depends purely on a preference of backward
* compatibility with either historic CJK or Western practice.
* Choosing single-width for these characters is easy to justify as
* the appropriate long-term solution, as the CJK practice of
* displaying these characters as double-width comes from historic
* implementation simplicity (8-bit encoded characters were displayed
* single-width and 16-bit ones double-width, even for Greek,
* Cyrillic, etc.) and not any typographic considerations.
*
* Much less clear is the choice of width for the Not East Asian
* (Neutral) class. Existing practice does not dictate a width for any
* of these characters. It would nevertheless make sense
* typographically to allocate two character cells to characters such
* as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
* represented adequately with a single-width glyph. The following
* routines at present merely assign a single-cell width to all
* neutral characters, in the interest of simplicity. This is not
* entirely satisfactory and should be reconsidered before
* establishing a formal standard in this area. At the moment, the
* decision which Not East Asian (Neutral) characters should be
* represented by double-width glyphs cannot yet be answered by
* applying a simple rule from the Unicode database content. Setting
* up a proper standard for the behavior of UTF-8 character terminals
* will require a careful analysis not only of each Unicode character,
* but also of each presentation form, something the author of these
* routines has avoided to do so far.
*
* http://www.unicode.org/unicode/reports/tr11/
*
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
*
* Permission to use, copy, modify, and distribute this software
* for any purpose and without fee is hereby granted. The author
* disclaims all warranties with regard to this software.
*
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
*/
struct interval {
int first;
int last;
};
/* sorted list of non-overlapping intervals of non-spacing characters */
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
static const struct interval combining[] = {
{ 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
{ 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
{ 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
{ 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
{ 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
{ 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
{ 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
{ 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
{ 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
{ 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
{ 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
{ 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
{ 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
{ 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
{ 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
{ 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
{ 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
{ 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
{ 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
{ 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
{ 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
{ 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
{ 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
{ 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
{ 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
{ 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
{ 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
{ 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
{ 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
{ 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
{ 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
{ 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
{ 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
{ 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
{ 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
{ 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
{ 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
{ 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
{ 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
{ 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
{ 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
{ 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
{ 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
{ 0xE0100, 0xE01EF }
};
/* auxiliary function for binary search in interval table */
static int bisearch(uint32_t ucs, const struct interval *table, int max) {
int min = 0;
int mid;
if ((int)ucs < table[0].first || (int)ucs > table[max].last)
return 0;
while (max >= min) {
mid = (min + max) / 2;
if ((int)ucs > table[mid].last)
min = mid + 1;
else if ((int)ucs < table[mid].first)
max = mid - 1;
else
return 1;
}
return 0;
}
/* The following two functions define the column width of an ISO 10646
* character as follows:
*
* - The null character (U+0000) has a column width of 0.
*
* - Other C0/C1 control characters and DEL will lead to a return
* value of -1.
*
* - Non-spacing and enclosing combining characters (general
* category code Mn or Me in the Unicode database) have a
* column width of 0.
*
* - SOFT HYPHEN (U+00AD) has a column width of 1.
*
* - Other format characters (general category code Cf in the Unicode
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
*
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
* have a column width of 0.
*
* - Spacing characters in the East Asian Wide (W) or East Asian
* Full-width (F) category as defined in Unicode Technical
* Report #11 have a column width of 2.
*
* - All remaining characters (including all printable
* ISO 8859-1 and WGL4 characters, Unicode control characters,
* etc.) have a column width of 1.
*
* This implementation assumes that uint32_t characters are encoded
* in ISO 10646.
*/
static int mk_wcwidth(uint32_t ucs)
{
/* test for 8-bit control characters */
if (ucs == 0)
return 0;
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
return -1;
/* binary search in table of non-spacing characters */
if (bisearch(ucs, combining,
sizeof(combining) / sizeof(struct interval) - 1))
return 0;
/* if we arrive here, ucs is not a combining or C0/C1 control character */
return 1 +
(ucs >= 0x1100 &&
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
ucs == 0x2329 || ucs == 0x232a ||
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
ucs != 0x303f) || /* CJK ... Yi */
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
(ucs >= 0x30000 && ucs <= 0x3fffd)));
}
#if 0 /* unused */
static int mk_wcswidth(const uint32_t *pwcs, size_t n)
{
int w, width = 0;
for (;*pwcs && n-- > 0; pwcs++)
if ((w = mk_wcwidth(*pwcs)) < 0)
return -1;
else
width += w;
return width;
}
/*
* The following functions are the same as mk_wcwidth() and
* mk_wcswidth(), except that spacing characters in the East Asian
* Ambiguous (A) category as defined in Unicode Technical Report #11
* have a column width of 2. This variant might be useful for users of
* CJK legacy encodings who want to migrate to UCS without changing
* the traditional terminal character-width behaviour. It is not
* otherwise recommended for general use.
*/
static int mk_wcwidth_cjk(uint32_t ucs)
{
/* sorted list of non-overlapping intervals of East Asian Ambiguous
* characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
static const struct interval ambiguous[] = {
{ 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
{ 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
{ 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
{ 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
{ 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
{ 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
{ 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
{ 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
{ 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
{ 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
{ 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
{ 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
{ 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
{ 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
{ 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
{ 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
{ 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
{ 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
{ 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
{ 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
{ 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
{ 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
{ 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
{ 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
{ 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
{ 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
{ 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
{ 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
{ 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
{ 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
{ 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
{ 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
{ 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
{ 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
{ 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
{ 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
{ 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
{ 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
{ 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
{ 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
{ 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
{ 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
{ 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
{ 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
{ 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
{ 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
{ 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
{ 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
{ 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
{ 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
{ 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
{ 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
};
/* binary search in table of non-spacing characters */
if (bisearch(ucs, ambiguous,
sizeof(ambiguous) / sizeof(struct interval) - 1))
return 2;
return mk_wcwidth(ucs);
}
static int mk_wcswidth_cjk(const uint32_t *pwcs, size_t n)
{
int w, width = 0;
for (;*pwcs && n-- > 0; pwcs++)
if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
return -1;
else
width += w;
return width;
}
#endif
/* ################################
* ### The rest added by Paul Evans */
INTERNAL int vterm_unicode_width(uint32_t codepoint)
{
return mk_wcwidth(codepoint);
}
INTERNAL int vterm_unicode_is_combining(uint32_t codepoint)
{
return bisearch(codepoint, combining, sizeof(combining) / sizeof(struct interval) - 1);
}

47
src/libvterm/src/utf8.h Normal file
View File

@@ -0,0 +1,47 @@
/* The following functions copied and adapted from libtermkey
*
* http://www.leonerd.org.uk/code/libtermkey/
*/
unsigned int utf8_seqlen(long codepoint);
#if defined(DEFINE_INLINES) || USE_INLINE
INLINE unsigned int utf8_seqlen(long codepoint)
{
if(codepoint < 0x0000080) return 1;
if(codepoint < 0x0000800) return 2;
if(codepoint < 0x0010000) return 3;
if(codepoint < 0x0200000) return 4;
if(codepoint < 0x4000000) return 5;
return 6;
}
#endif
/* Does NOT NUL-terminate the buffer */
int fill_utf8(long codepoint, char *str);
#if defined(DEFINE_INLINES) || USE_INLINE
INLINE int fill_utf8(long codepoint, char *str)
{
int nbytes = utf8_seqlen(codepoint);
/* This is easier done backwards */
int b = nbytes;
while(b > 1) {
b--;
str[b] = 0x80 | (codepoint & 0x3f);
codepoint >>= 6;
}
switch(nbytes) {
case 1: str[0] = (codepoint & 0x7f); break;
case 2: str[0] = 0xc0 | (codepoint & 0x1f); break;
case 3: str[0] = 0xe0 | (codepoint & 0x0f); break;
case 4: str[0] = 0xf0 | (codepoint & 0x07); break;
case 5: str[0] = 0xf8 | (codepoint & 0x03); break;
case 6: str[0] = 0xfc | (codepoint & 0x01); break;
}
return nbytes;
}
#endif
/* end copy */

412
src/libvterm/src/vterm.c Normal file
View File

@@ -0,0 +1,412 @@
#define DEFINE_INLINES
#include "vterm_internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "utf8.h"
/*****************
* API functions *
*****************/
static void *default_malloc(size_t size, void *allocdata UNUSED)
{
void *ptr = malloc(size);
if(ptr)
memset(ptr, 0, size);
return ptr;
}
static void default_free(void *ptr, void *allocdata UNUSED)
{
free(ptr);
}
static VTermAllocatorFunctions default_allocator = {
&default_malloc, /* malloc */
&default_free /* free */
};
VTerm *vterm_new(int rows, int cols)
{
return vterm_new_with_allocator(rows, cols, &default_allocator, NULL);
}
VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata)
{
/* Need to bootstrap using the allocator function directly */
VTerm *vt = (*funcs->malloc)(sizeof(VTerm), allocdata);
vt->allocator = funcs;
vt->allocdata = allocdata;
vt->rows = rows;
vt->cols = cols;
vt->parser_state = NORMAL;
vt->parser_callbacks = NULL;
vt->cbdata = NULL;
vt->strbuffer_len = 64;
vt->strbuffer_cur = 0;
vt->strbuffer = vterm_allocator_malloc(vt, vt->strbuffer_len);
vt->outbuffer_len = 64;
vt->outbuffer_cur = 0;
vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len);
return vt;
}
void vterm_free(VTerm *vt)
{
if(vt->screen)
vterm_screen_free(vt->screen);
if(vt->state)
vterm_state_free(vt->state);
vterm_allocator_free(vt, vt->strbuffer);
vterm_allocator_free(vt, vt->outbuffer);
vterm_allocator_free(vt, vt);
}
INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size)
{
return (*vt->allocator->malloc)(size, vt->allocdata);
}
INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)
{
(*vt->allocator->free)(ptr, vt->allocdata);
}
void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp)
{
if(rowsp)
*rowsp = vt->rows;
if(colsp)
*colsp = vt->cols;
}
void vterm_set_size(VTerm *vt, int rows, int cols)
{
vt->rows = rows;
vt->cols = cols;
if(vt->parser_callbacks && vt->parser_callbacks->resize)
(*vt->parser_callbacks->resize)(rows, cols, vt->cbdata);
}
int vterm_get_utf8(const VTerm *vt)
{
return vt->mode.utf8;
}
void vterm_set_utf8(VTerm *vt, int is_utf8)
{
vt->mode.utf8 = is_utf8;
}
INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len)
{
if(len > vt->outbuffer_len - vt->outbuffer_cur) {
DEBUG_LOG("vterm_push_output(): buffer overflow; truncating output\n");
len = vt->outbuffer_len - vt->outbuffer_cur;
}
memcpy(vt->outbuffer + vt->outbuffer_cur, bytes, len);
vt->outbuffer_cur += len;
}
static int outbuffer_is_full(VTerm *vt)
{
return vt->outbuffer_cur >= vt->outbuffer_len - 1;
}
#if _XOPEN_SOURCE >= 500 || _ISOC99_SOURCE || _BSD_SOURCE
# undef VSNPRINTF
# define VSNPRINTF vsnprintf
#else
# ifdef VSNPRINTF
/* Use a provided vsnprintf() function. */
int VSNPRINTF(char *str, size_t str_m, const char *fmt, va_list ap);
# endif
#endif
INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args)
{
int written;
#ifndef VSNPRINTF
/* When vsnprintf() is not available (C90) fall back to vsprintf(). */
char buffer[1024]; /* 1Kbyte is enough for everybody, right? */
#endif
if(outbuffer_is_full(vt)) {
DEBUG_LOG("vterm_push_output(): buffer overflow; truncating output\n");
return;
}
#ifdef VSNPRINTF
written = VSNPRINTF(vt->outbuffer + vt->outbuffer_cur,
vt->outbuffer_len - vt->outbuffer_cur,
format, args);
if(written == (int)(vt->outbuffer_len - vt->outbuffer_cur)) {
/* output was truncated */
vt->outbuffer_cur = vt->outbuffer_len - 1;
}
else
vt->outbuffer_cur += written;
#else
written = vsprintf(buffer, format, args);
if(written >= (int)(vt->outbuffer_len - vt->outbuffer_cur)) {
/* output was truncated */
written = vt->outbuffer_len - vt->outbuffer_cur;
}
if (written > 0)
{
strncpy(vt->outbuffer + vt->outbuffer_cur, buffer, written + 1);
vt->outbuffer_cur += written;
}
#endif
}
INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)
{
va_list args;
va_start(args, format);
vterm_push_output_vsprintf(vt, format, args);
va_end(args);
}
INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...)
{
size_t orig_cur = vt->outbuffer_cur;
va_list args;
if(ctrl >= 0x80 && !vt->mode.ctrl8bit)
vterm_push_output_sprintf(vt, ESC_S "%c", ctrl - 0x40);
else
vterm_push_output_sprintf(vt, "%c", ctrl);
va_start(args, fmt);
vterm_push_output_vsprintf(vt, fmt, args);
va_end(args);
if(outbuffer_is_full(vt))
vt->outbuffer_cur = orig_cur;
}
INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...)
{
size_t orig_cur = vt->outbuffer_cur;
va_list args;
if(!vt->mode.ctrl8bit)
vterm_push_output_sprintf(vt, ESC_S "%c", C1_DCS - 0x40);
else
vterm_push_output_sprintf(vt, "%c", C1_DCS);
va_start(args, fmt);
vterm_push_output_vsprintf(vt, fmt, args);
va_end(args);
vterm_push_output_sprintf_ctrl(vt, C1_ST, "");
if(outbuffer_is_full(vt))
vt->outbuffer_cur = orig_cur;
}
size_t vterm_output_get_buffer_size(const VTerm *vt)
{
return vt->outbuffer_len;
}
size_t vterm_output_get_buffer_current(const VTerm *vt)
{
return vt->outbuffer_cur;
}
size_t vterm_output_get_buffer_remaining(const VTerm *vt)
{
return vt->outbuffer_len - vt->outbuffer_cur;
}
size_t vterm_output_read(VTerm *vt, char *buffer, size_t len)
{
if(len > vt->outbuffer_cur)
len = vt->outbuffer_cur;
memcpy(buffer, vt->outbuffer, len);
if(len < vt->outbuffer_cur)
memmove(vt->outbuffer, vt->outbuffer + len, vt->outbuffer_cur - len);
vt->outbuffer_cur -= len;
return len;
}
void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user)
{
vt->parser_callbacks = callbacks;
vt->cbdata = user;
}
void *vterm_parser_get_cbdata(VTerm *vt)
{
return vt->cbdata;
}
VTermValueType vterm_get_attr_type(VTermAttr attr)
{
switch(attr) {
case VTERM_ATTR_BOLD: return VTERM_VALUETYPE_BOOL;
case VTERM_ATTR_UNDERLINE: return VTERM_VALUETYPE_INT;
case VTERM_ATTR_ITALIC: return VTERM_VALUETYPE_BOOL;
case VTERM_ATTR_BLINK: return VTERM_VALUETYPE_BOOL;
case VTERM_ATTR_REVERSE: return VTERM_VALUETYPE_BOOL;
case VTERM_ATTR_STRIKE: return VTERM_VALUETYPE_BOOL;
case VTERM_ATTR_FONT: return VTERM_VALUETYPE_INT;
case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR;
case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR;
}
return 0; /* UNREACHABLE */
}
VTermValueType vterm_get_prop_type(VTermProp prop)
{
switch(prop) {
case VTERM_PROP_CURSORVISIBLE: return VTERM_VALUETYPE_BOOL;
case VTERM_PROP_CURSORBLINK: return VTERM_VALUETYPE_BOOL;
case VTERM_PROP_ALTSCREEN: return VTERM_VALUETYPE_BOOL;
case VTERM_PROP_TITLE: return VTERM_VALUETYPE_STRING;
case VTERM_PROP_ICONNAME: return VTERM_VALUETYPE_STRING;
case VTERM_PROP_REVERSE: return VTERM_VALUETYPE_BOOL;
case VTERM_PROP_CURSORSHAPE: return VTERM_VALUETYPE_INT;
case VTERM_PROP_MOUSE: return VTERM_VALUETYPE_INT;
}
return 0; /* UNREACHABLE */
}
void vterm_scroll_rect(VTermRect rect,
int downward,
int rightward,
int (*moverect)(VTermRect src, VTermRect dest, void *user),
int (*eraserect)(VTermRect rect, int selective, void *user),
void *user)
{
VTermRect src;
VTermRect dest;
if(abs(downward) >= rect.end_row - rect.start_row ||
abs(rightward) >= rect.end_col - rect.start_col) {
/* Scroll more than area; just erase the lot */
(*eraserect)(rect, 0, user);
return;
}
if(rightward >= 0) {
/* rect: [XXX................]
* src: [----------------]
* dest: [----------------]
*/
dest.start_col = rect.start_col;
dest.end_col = rect.end_col - rightward;
src.start_col = rect.start_col + rightward;
src.end_col = rect.end_col;
}
else {
/* rect: [................XXX]
* src: [----------------]
* dest: [----------------]
*/
int leftward = -rightward;
dest.start_col = rect.start_col + leftward;
dest.end_col = rect.end_col;
src.start_col = rect.start_col;
src.end_col = rect.end_col - leftward;
}
if(downward >= 0) {
dest.start_row = rect.start_row;
dest.end_row = rect.end_row - downward;
src.start_row = rect.start_row + downward;
src.end_row = rect.end_row;
}
else {
int upward = -downward;
dest.start_row = rect.start_row + upward;
dest.end_row = rect.end_row;
src.start_row = rect.start_row;
src.end_row = rect.end_row - upward;
}
if(moverect)
(*moverect)(dest, src, user);
if(downward > 0)
rect.start_row = rect.end_row - downward;
else if(downward < 0)
rect.end_row = rect.start_row - downward;
if(rightward > 0)
rect.start_col = rect.end_col - rightward;
else if(rightward < 0)
rect.end_col = rect.start_col - rightward;
(*eraserect)(rect, 0, user);
}
void vterm_copy_cells(VTermRect dest,
VTermRect src,
void (*copycell)(VTermPos dest, VTermPos src, void *user),
void *user)
{
int downward = src.start_row - dest.start_row;
int rightward = src.start_col - dest.start_col;
int init_row, test_row, init_col, test_col;
int inc_row, inc_col;
VTermPos pos;
if(downward < 0) {
init_row = dest.end_row - 1;
test_row = dest.start_row - 1;
inc_row = -1;
}
else /* downward >= 0 */ {
init_row = dest.start_row;
test_row = dest.end_row;
inc_row = +1;
}
if(rightward < 0) {
init_col = dest.end_col - 1;
test_col = dest.start_col - 1;
inc_col = -1;
}
else /* rightward >= 0 */ {
init_col = dest.start_col;
test_col = dest.end_col;
inc_col = +1;
}
for(pos.row = init_row; pos.row != test_row; pos.row += inc_row)
for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) {
VTermPos srcpos;
srcpos.row = pos.row + downward;
srcpos.col = pos.col + rightward;
(*copycell)(pos, srcpos, user);
}
}

View File

@@ -0,0 +1,237 @@
#ifndef __VTERM_INTERNAL_H__
#define __VTERM_INTERNAL_H__
#include "vterm.h"
#include <stdarg.h>
#if defined(__GNUC__)
# define INTERNAL __attribute__((visibility("internal")))
# define UNUSED __attribute__((unused))
#else
# define INTERNAL
# define UNUSED
#endif
#ifdef DEBUG
# define DEBUG_LOG(s) fprintf(stderr, s)
# define DEBUG_LOG1(s, a) fprintf(stderr, s, a)
# define DEBUG_LOG2(s, a, b) fprintf(stderr, s, a, b)
# define DEBUG_LOG3(s, a, b, c) fprintf(stderr, s, a, b, c)
#else
# define DEBUG_LOG(s)
# define DEBUG_LOG1(s, a)
# define DEBUG_LOG2(s, a, b)
# define DEBUG_LOG3(s, a, b, c)
#endif
#define ESC_S "\x1b"
typedef struct VTermEncoding VTermEncoding;
typedef struct {
VTermEncoding *enc;
/* This size should be increased if required by other stateful encodings */
char data[4*sizeof(uint32_t)];
} VTermEncodingInstance;
struct VTermPen
{
VTermColor fg;
VTermColor bg;
unsigned int bold:1;
unsigned int underline:2;
unsigned int italic:1;
unsigned int blink:1;
unsigned int reverse:1;
unsigned int strike:1;
unsigned int font:4; /* To store 0-9 */
};
int vterm_color_equal(VTermColor a, VTermColor b);
#if defined(DEFINE_INLINES) || USE_INLINE
INLINE int vterm_color_equal(VTermColor a, VTermColor b)
{
return a.red == b.red && a.green == b.green && a.blue == b.blue;
}
#endif
struct VTermState
{
VTerm *vt;
const VTermStateCallbacks *callbacks;
void *cbdata;
const VTermParserCallbacks *fallbacks;
void *fbdata;
int rows;
int cols;
/* Current cursor position */
VTermPos pos;
int at_phantom; /* True if we're on the "81st" phantom column to defer a wraparound */
int scrollregion_top;
int scrollregion_bottom; /* -1 means unbounded */
#define SCROLLREGION_BOTTOM(state) ((state)->scrollregion_bottom > -1 ? (state)->scrollregion_bottom : (state)->rows)
int scrollregion_left;
#define SCROLLREGION_LEFT(state) ((state)->mode.leftrightmargin ? (state)->scrollregion_left : 0)
int scrollregion_right; /* -1 means unbounded */
#define SCROLLREGION_RIGHT(state) ((state)->mode.leftrightmargin && (state)->scrollregion_right > -1 ? (state)->scrollregion_right : (state)->cols)
/* Bitvector of tab stops */
unsigned char *tabstops;
VTermLineInfo *lineinfo;
#define ROWWIDTH(state,row) ((state)->lineinfo[(row)].doublewidth ? ((state)->cols / 2) : (state)->cols)
#define THISROWWIDTH(state) ROWWIDTH(state, (state)->pos.row)
/* Mouse state */
int mouse_col, mouse_row;
int mouse_buttons;
int mouse_flags;
#define MOUSE_WANT_CLICK 0x01
#define MOUSE_WANT_DRAG 0x02
#define MOUSE_WANT_MOVE 0x04
enum { MOUSE_X10, MOUSE_UTF8, MOUSE_SGR, MOUSE_RXVT } mouse_protocol;
/* Last glyph output, for Unicode recombining purposes */
uint32_t *combine_chars;
size_t combine_chars_size; /* Number of ELEMENTS in the above */
int combine_width; /* The width of the glyph above */
VTermPos combine_pos; /* Position before movement */
struct {
unsigned int keypad:1;
unsigned int cursor:1;
unsigned int autowrap:1;
unsigned int insert:1;
unsigned int newline:1;
unsigned int cursor_visible:1;
unsigned int cursor_blink:1;
unsigned int cursor_shape:2;
unsigned int alt_screen:1;
unsigned int origin:1;
unsigned int screen:1;
unsigned int leftrightmargin:1;
unsigned int bracketpaste:1;
} mode;
VTermEncodingInstance encoding[4], encoding_utf8;
int gl_set, gr_set, gsingle_set;
struct VTermPen pen;
VTermColor default_fg;
VTermColor default_bg;
VTermColor colors[16]; /* Store the 8 ANSI and the 8 ANSI high-brights only */
int fg_index;
int bg_index;
int bold_is_highbright;
unsigned int protected_cell : 1;
/* Saved state under DEC mode 1048/1049 */
struct {
VTermPos pos;
struct VTermPen pen;
struct {
int cursor_visible:1;
int cursor_blink:1;
unsigned int cursor_shape:2;
} mode;
} saved;
};
struct VTerm
{
VTermAllocatorFunctions *allocator;
void *allocdata;
int rows;
int cols;
struct {
unsigned int utf8:1;
unsigned int ctrl8bit:1;
} mode;
enum VTermParserState {
NORMAL,
CSI,
OSC,
DCS,
ESC,
ESC_IN_OSC,
ESC_IN_DCS
} parser_state;
const VTermParserCallbacks *parser_callbacks;
void *cbdata;
/* len == malloc()ed size; cur == number of valid bytes */
char *strbuffer;
size_t strbuffer_len;
size_t strbuffer_cur;
char *outbuffer;
size_t outbuffer_len;
size_t outbuffer_cur;
VTermState *state;
VTermScreen *screen;
};
struct VTermEncoding {
void (*init) (VTermEncoding *enc, void *data);
void (*decode)(VTermEncoding *enc, void *data,
uint32_t cp[], int *cpi, int cplen,
const char bytes[], size_t *pos, size_t len);
};
typedef enum {
ENC_UTF8,
ENC_SINGLE_94
} VTermEncodingType;
void *vterm_allocator_malloc(VTerm *vt, size_t size);
void vterm_allocator_free(VTerm *vt, void *ptr);
void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len);
void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args);
void vterm_push_output_sprintf(VTerm *vt, const char *format, ...);
void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...);
void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...);
void vterm_state_free(VTermState *state);
void vterm_state_newpen(VTermState *state);
void vterm_state_resetpen(VTermState *state);
void vterm_state_setpen(VTermState *state, const long args[], int argcount);
int vterm_state_getpen(VTermState *state, long args[], int argcount);
void vterm_state_savepen(VTermState *state, int save);
enum {
C1_SS3 = 0x8f,
C1_DCS = 0x90,
C1_CSI = 0x9b,
C1_ST = 0x9c
};
void vterm_state_push_output_sprintf_CSI(VTermState *vts, const char *format, ...);
void vterm_screen_free(VTermScreen *screen);
VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation);
int vterm_unicode_width(uint32_t codepoint);
int vterm_unicode_is_combining(uint32_t codepoint);
#endif

View File

@@ -0,0 +1,200 @@
INIT
UTF8 0
WANTPARSER
!Basic text
PUSH "hello"
text 0x68, 0x65, 0x6c, 0x6c, 0x6f
!C0
PUSH "\x03"
control 3
PUSH "\x1f"
control 0x1f
!C1 8bit
PUSH "\x83"
control 0x83
PUSH "\x9f"
control 0x9f
!C1 7bit
PUSH "\e\x43"
control 0x83
PUSH "\e\x5f"
control 0x9f
!High bytes
PUSH "\xa0\xcc\xfe"
text 0xa0, 0xcc, 0xfe
!Mixed
PUSH "1\n2"
text 0x31
control 10
text 0x32
!Escape
PUSH "\e="
escape "="
!Escape 2-byte
PUSH "\e(X"
escape "(X"
!Split write Escape
PUSH "\e("
PUSH "Y"
escape "(Y"
!Escape cancels Escape, starts another
PUSH "\e(\e)Z"
escape ")Z"
!CAN cancels Escape, returns to normal mode
PUSH "\e(\x{18}AB"
text 0x41, 0x42
!C0 in Escape interrupts and continues
PUSH "\e(\nX"
control 10
escape "(X"
!CSI 0 args
PUSH "\e[a"
csi 0x61 *
!CSI 1 arg
PUSH "\e[9b"
csi 0x62 9
!CSI 2 args
PUSH "\e[3;4c"
csi 0x63 3,4
!CSI 1 arg 1 sub
PUSH "\e[1:2c"
csi 0x63 1+,2
!CSI many digits
PUSH "\e[678d"
csi 0x64 678
!CSI leading zero
PUSH "\e[007e"
csi 0x65 7
!CSI qmark
PUSH "\e[?2;7f"
csi 0x66 L=3f 2,7
!CSI greater
PUSH "\e[>c"
csi 0x63 L=3e *
!CSI SP
PUSH "\e[12 q"
csi 0x71 12 I=20
!Mixed CSI
PUSH "A\e[8mB"
text 0x41
csi 0x6d 8
text 0x42
!Split write
PUSH "\e"
PUSH "[a"
csi 0x61 *
PUSH "foo\e["
text 0x66, 0x6f, 0x6f
PUSH "4b"
csi 0x62 4
PUSH "\e[12;"
PUSH "3c"
csi 0x63 12,3
!Escape cancels CSI, starts Escape
PUSH "\e[123\e9"
escape "9"
!CAN cancels CSI, returns to normal mode
PUSH "\e[12\x{18}AB"
text 0x41, 0x42
!C0 in Escape interrupts and continues
PUSH "\e[12\n;3X"
control 10
csi 0x58 12,3
!OSC BEL
PUSH "\e]1;Hello\x07"
osc "1;Hello"
!OSC ST (7bit)
PUSH "\e]1;Hello\e\\"
osc "1;Hello"
!OSC ST (8bit)
PUSH "\x{9d}1;Hello\x9c"
osc "1;Hello"
!Escape cancels OSC, starts Escape
PUSH "\e]Something\e9"
escape "9"
!CAN cancels OSC, returns to normal mode
PUSH "\e]12\x{18}AB"
text 0x41, 0x42
!C0 in OSC interrupts and continues
PUSH "\e]2;\nBye\x07"
control 10
osc "2;Bye"
!DCS BEL
PUSH "\ePHello\x07"
dcs "Hello"
!DCS ST (7bit)
PUSH "\ePHello\e\\"
dcs "Hello"
!DCS ST (8bit)
PUSH "\x{90}Hello\x9c"
dcs "Hello"
!Escape cancels DCS, starts Escape
PUSH "\ePSomething\e9"
escape "9"
!CAN cancels DCS, returns to normal mode
PUSH "\eP12\x{18}AB"
text 0x41, 0x42
!C0 in OSC interrupts and continues
PUSH "\ePBy\ne\x07"
control 10
dcs "Bye"
!NUL ignored
PUSH "\x{00}"
!NUL ignored within CSI
PUSH "\e[12\x{00}3m"
csi 0x6d 123
!DEL ignored
PUSH "\x{7f}"
!DEL ignored within CSI
PUSH "\e[12\x{7f}3m"
csi 0x6d 123
!DEL inside text"
PUSH "AB\x{7f}C"
text 0x41,0x42
text 0x43

View File

@@ -0,0 +1,122 @@
INIT
WANTENCODING
!Low
ENCIN "123"
encout 0x31,0x32,0x33
# We want to prove the UTF-8 parser correctly handles all the sequences.
# Easy way to do this is to check it does low/high boundary cases, as that
# leaves only two for each sequence length
#
# These ranges are therefore:
#
# Two bytes:
# U+0080 = 000 10000000 => 00010 000000
# => 11000010 10000000 = C2 80
# U+07FF = 111 11111111 => 11111 111111
# => 11011111 10111111 = DF BF
#
# Three bytes:
# U+0800 = 00001000 00000000 => 0000 100000 000000
# => 11100000 10100000 10000000 = E0 A0 80
# U+FFFD = 11111111 11111101 => 1111 111111 111101
# => 11101111 10111111 10111101 = EF BF BD
# (We avoid U+FFFE and U+FFFF as they're invalid codepoints)
#
# Four bytes:
# U+10000 = 00001 00000000 00000000 => 000 010000 000000 000000
# => 11110000 10010000 10000000 10000000 = F0 90 80 80
# U+1FFFFF = 11111 11111111 11111111 => 111 111111 111111 111111
# => 11110111 10111111 10111111 10111111 = F7 BF BF BF
!2 byte
ENCIN "\xC2\x80\xDF\xBF"
encout 0x0080, 0x07FF
!3 byte
ENCIN "\xE0\xA0\x80\xEF\xBF\xBD"
encout 0x0800,0xFFFD
!4 byte
ENCIN "\xF0\x90\x80\x80\xF7\xBF\xBF\xBF"
encout 0x10000,0x1fffff
# Next up, we check some invalid sequences
# + Early termination (back to low bytes too soon)
# + Early restart (another sequence introduction before the previous one was finished)
!Early termination
ENCIN "\xC2!"
encout 0xfffd,0x21
ENCIN "\xE0!\xE0\xA0!"
encout 0xfffd,0x21,0xfffd,0x21
ENCIN "\xF0!\xF0\x90!\xF0\x90\x80!"
encout 0xfffd,0x21,0xfffd,0x21,0xfffd,0x21
!Early restart
ENCIN "\xC2\xC2\x90"
encout 0xfffd,0x0090
ENCIN "\xE0\xC2\x90\xE0\xA0\xC2\x90"
encout 0xfffd,0x0090,0xfffd,0x0090
ENCIN "\xF0\xC2\x90\xF0\x90\xC2\x90\xF0\x90\x80\xC2\x90"
encout 0xfffd,0x0090,0xfffd,0x0090,0xfffd,0x0090
# Test the overlong sequences by giving an overlong encoding of U+0000 and
# an encoding of the highest codepoint still too short
#
# Two bytes:
# U+0000 = C0 80
# U+007F = 000 01111111 => 00001 111111 =>
# => 11000001 10111111 => C1 BF
#
# Three bytes:
# U+0000 = E0 80 80
# U+07FF = 00000111 11111111 => 0000 011111 111111
# => 11100000 10011111 10111111 = E0 9F BF
#
# Four bytes:
# U+0000 = F0 80 80 80
# U+FFFF = 11111111 11111111 => 000 001111 111111 111111
# => 11110000 10001111 10111111 10111111 = F0 8F BF BF
!Overlong
ENCIN "\xC0\x80\xC1\xBF"
encout 0xfffd,0xfffd
ENCIN "\xE0\x80\x80\xE0\x9F\xBF"
encout 0xfffd,0xfffd
ENCIN "\xF0\x80\x80\x80\xF0\x8F\xBF\xBF"
encout 0xfffd,0xfffd
# UTF-16 surrogates U+D800 and U+DFFF
!UTF-16 Surrogates
ENCIN "\xED\xA0\x80\xED\xBF\xBF"
encout 0xfffd,0xfffd
!Split write
ENCIN "\xC2"
ENCIN "\xA0"
encout 0x000A0
ENCIN "\xE0"
ENCIN "\xA0\x80"
encout 0x00800
ENCIN "\xE0\xA0"
ENCIN "\x80"
encout 0x00800
ENCIN "\xF0"
ENCIN "\x90\x80\x80"
encout 0x10000
ENCIN "\xF0\x90"
ENCIN "\x80\x80"
encout 0x10000
ENCIN "\xF0\x90\x80"
ENCIN "\x80"
encout 0x10000

View File

@@ -0,0 +1,55 @@
INIT
UTF8 1
WANTSTATE g
!Low
RESET
PUSH "ABC"
putglyph 0x41 1 0,0
putglyph 0x42 1 0,1
putglyph 0x43 1 0,2
!UTF-8 1 char
# U+00C1 = 0xC3 0x81 name: LATIN CAPITAL LETTER A WITH ACUTE
# U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE
RESET
PUSH "\xC3\x81\xC3\xA9"
putglyph 0xc1 1 0,0
putglyph 0xe9 1 0,1
!UTF-8 wide char
# U+FF10 = 0xEF 0xBC 0x90 name: FULLWIDTH DIGIT ZERO
RESET
PUSH "\xEF\xBC\x90 "
putglyph 0xff10 2 0,0
putglyph 0x20 1 0,2
!UTF-8 combining chars
# U+0301 = 0xCC 0x81 name: COMBINING ACUTE
RESET
PUSH "e\xCC\x81Z"
putglyph 0x65,0x301 1 0,0
putglyph 0x5a 1 0,1
!Combining across buffers
RESET
PUSH "e"
putglyph 0x65 1 0,0
PUSH "\xCC\x81Z"
putglyph 0x65,0x301 1 0,0
putglyph 0x5a 1 0,1
RESET
PUSH "e"
putglyph 0x65 1 0,0
PUSH "\xCC\x81"
putglyph 0x65,0x301 1 0,0
PUSH "\xCC\x82"
putglyph 0x65,0x301,0x302 1 0,0
!DECSCA protected
RESET
PUSH "A\e[1\"qB\e[2\"qC"
putglyph 0x41 1 0,0
putglyph 0x42 1 0,1 prot
putglyph 0x43 1 0,2

View File

@@ -0,0 +1,224 @@
INIT
UTF8 1
WANTSTATE
!Implicit
PUSH "ABC"
?cursor = 0,3
!Backspace
PUSH "\b"
?cursor = 0,2
!Horizontal Tab
PUSH "\t"
?cursor = 0,8
!Carriage Return
PUSH "\r"
?cursor = 0,0
!Linefeed
PUSH "\n"
?cursor = 1,0
!Backspace bounded by lefthand edge
PUSH "\e[4;2H"
?cursor = 3,1
PUSH "\b"
?cursor = 3,0
PUSH "\b"
?cursor = 3,0
!Backspace cancels phantom
PUSH "\e[4;80H"
?cursor = 3,79
PUSH "X"
?cursor = 3,79
PUSH "\b"
?cursor = 3,78
!HT bounded by righthand edge
PUSH "\e[1;78H"
?cursor = 0,77
PUSH "\t"
?cursor = 0,79
PUSH "\t"
?cursor = 0,79
RESET
!Index
PUSH "ABC\eD"
?cursor = 1,3
!Reverse Index
PUSH "\eM"
?cursor = 0,3
!Newline
PUSH "\eE"
?cursor = 1,0
RESET
!Cursor Forward
PUSH "\e[B"
?cursor = 1,0
PUSH "\e[3B"
?cursor = 4,0
PUSH "\e[0B"
?cursor = 5,0
!Cursor Down
PUSH "\e[C"
?cursor = 5,1
PUSH "\e[3C"
?cursor = 5,4
PUSH "\e[0C"
?cursor = 5,5
!Cursor Up
PUSH "\e[A"
?cursor = 4,5
PUSH "\e[3A"
?cursor = 1,5
PUSH "\e[0A"
?cursor = 0,5
!Cursor Backward
PUSH "\e[D"
?cursor = 0,4
PUSH "\e[3D"
?cursor = 0,1
PUSH "\e[0D"
?cursor = 0,0
!Cursor Next Line
PUSH " "
?cursor = 0,3
PUSH "\e[E"
?cursor = 1,0
PUSH " "
?cursor = 1,3
PUSH "\e[2E"
?cursor = 3,0
PUSH "\e[0E"
?cursor = 4,0
!Cursor Previous Line
PUSH " "
?cursor = 4,3
PUSH "\e[F"
?cursor = 3,0
PUSH " "
?cursor = 3,3
PUSH "\e[2F"
?cursor = 1,0
PUSH "\e[0F"
?cursor = 0,0
!Cursor Horizonal Absolute
PUSH "\n"
?cursor = 1,0
PUSH "\e[20G"
?cursor = 1,19
PUSH "\e[G"
?cursor = 1,0
!Cursor Position
PUSH "\e[10;5H"
?cursor = 9,4
PUSH "\e[8H"
?cursor = 7,0
PUSH "\e[H"
?cursor = 0,0
!Cursor Position cancels phantom
PUSH "\e[10;78H"
?cursor = 9,77
PUSH "ABC"
?cursor = 9,79
PUSH "\e[10;80H"
PUSH "C"
?cursor = 9,79
PUSH "X"
?cursor = 10,1
RESET
!Bounds Checking
PUSH "\e[A"
?cursor = 0,0
PUSH "\e[D"
?cursor = 0,0
PUSH "\e[25;80H"
?cursor = 24,79
PUSH "\e[B"
?cursor = 24,79
PUSH "\e[C"
?cursor = 24,79
PUSH "\e[E"
?cursor = 24,0
PUSH "\e[H"
?cursor = 0,0
PUSH "\e[F"
?cursor = 0,0
PUSH "\e[999G"
?cursor = 0,79
PUSH "\e[99;99H"
?cursor = 24,79
RESET
!Horizontal Position Absolute
PUSH "\e[5`"
?cursor = 0,4
!Horizontal Position Relative
PUSH "\e[3a"
?cursor = 0,7
!Horizontal Position Backward
PUSH "\e[3j"
?cursor = 0,4
!Horizontal and Vertical Position
PUSH "\e[3;3f"
?cursor = 2,2
!Vertical Position Absolute
PUSH "\e[5d"
?cursor = 4,2
!Vertical Position Relative
PUSH "\e[2e"
?cursor = 6,2
!Vertical Position Backward
PUSH "\e[2k"
?cursor = 4,2
RESET
!Horizontal Tab
PUSH "\t"
?cursor = 0,8
PUSH " "
?cursor = 0,11
PUSH "\t"
?cursor = 0,16
PUSH " "
?cursor = 0,23
PUSH "\t"
?cursor = 0,24
PUSH " "
?cursor = 0,32
PUSH "\t"
?cursor = 0,40
!Cursor Horizontal Tab
PUSH "\e[I"
?cursor = 0,48
PUSH "\e[2I"
?cursor = 0,64
!Cursor Backward Tab
PUSH "\e[Z"
?cursor = 0,56
PUSH "\e[2Z"
?cursor = 0,40

View File

@@ -0,0 +1,150 @@
INIT
UTF8 1
WANTSTATE s
!Linefeed
PUSH "\n"x24
?cursor = 24,0
PUSH "\n"
scrollrect 0..25,0..80 => +1,+0
?cursor = 24,0
RESET
!Index
PUSH "\e[25H"
PUSH "\eD"
scrollrect 0..25,0..80 => +1,+0
RESET
!Reverse Index
PUSH "\eM"
scrollrect 0..25,0..80 => -1,+0
RESET
!Linefeed in DECSTBM
PUSH "\e[1;10r"
?cursor = 0,0
PUSH "\n"x9
?cursor = 9,0
PUSH "\n"
scrollrect 0..10,0..80 => +1,+0
?cursor = 9,0
!Linefeed outside DECSTBM
PUSH "\e[20H"
?cursor = 19,0
PUSH "\n"
?cursor = 20,0
!Index in DECSTBM
PUSH "\e[10H"
PUSH "\e[9;10r"
PUSH "\eM"
?cursor = 8,0
PUSH "\eM"
scrollrect 8..10,0..80 => -1,+0
!Reverse Index in DECSTBM
PUSH "\e[25H"
?cursor = 24,0
PUSH "\n"
# no scrollrect
?cursor = 24,0
!Linefeed in DECSTBM+DECSLRM
PUSH "\e[?69h"
PUSH "\e[3;10r\e[10;40s"
PUSH "\e[10;10H\n"
scrollrect 2..10,9..40 => +1,+0
!IND/RI in DECSTBM+DECSLRM
PUSH "\eD"
scrollrect 2..10,9..40 => +1,+0
PUSH "\e[3;10H\eM"
scrollrect 2..10,9..40 => -1,+0
!DECRQSS on DECSTBM
PUSH "\eP\$qr\e\\"
output "\eP1\$r3;10r\e\\"
!DECRQSS on DECSLRM
PUSH "\eP\$qs\e\\"
output "\eP1\$r10;40s\e\\"
!Setting invalid DECSLRM with !DECVSSM is still rejected
PUSH "\e[?69l\e[;0s\e[?69h"
RESET
!Scroll Down
PUSH "\e[S"
scrollrect 0..25,0..80 => +1,+0
?cursor = 0,0
PUSH "\e[2S"
scrollrect 0..25,0..80 => +2,+0
?cursor = 0,0
PUSH "\e[100S"
scrollrect 0..25,0..80 => +25,+0
!Scroll Up
PUSH "\e[T"
scrollrect 0..25,0..80 => -1,+0
?cursor = 0,0
PUSH "\e[2T"
scrollrect 0..25,0..80 => -2,+0
?cursor = 0,0
PUSH "\e[100T"
scrollrect 0..25,0..80 => -25,+0
!SD/SU in DECSTBM
PUSH "\e[5;20r"
PUSH "\e[S"
scrollrect 4..20,0..80 => +1,+0
PUSH "\e[T"
scrollrect 4..20,0..80 => -1,+0
RESET
!SD/SU in DECSTBM+DECSLRM
PUSH "\e[?69h"
PUSH "\e[3;10r\e[10;40s"
?cursor = 0,0
PUSH "\e[3;10H"
?cursor = 2,9
PUSH "\e[S"
scrollrect 2..10,9..40 => +1,+0
PUSH "\e[?69l"
PUSH "\e[S"
scrollrect 2..10,0..80 => +1,+0
!Invalid boundaries
RESET
PUSH "\e[100;105r\eD"
PUSH "\e[5;2r\eD"
RESET
WANTSTATE -s+me
!Scroll Down move+erase emulation
PUSH "\e[S"
moverect 1..25,0..80 -> 0..24,0..80
erase 24..25,0..80
?cursor = 0,0
PUSH "\e[2S"
moverect 2..25,0..80 -> 0..23,0..80
erase 23..25,0..80
?cursor = 0,0
!Scroll Up move+erase emulation
PUSH "\e[T"
moverect 0..24,0..80 -> 1..25,0..80
erase 0..1,0..80
?cursor = 0,0
PUSH "\e[2T"
moverect 0..23,0..80 -> 2..25,0..80
erase 0..2,0..80
?cursor = 0,0

View File

@@ -0,0 +1,300 @@
INIT
UTF8 1
WANTSTATE se
!ICH
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ACD"
PUSH "\e[2D"
?cursor = 0,1
PUSH "\e[@"
scrollrect 0..1,1..80 => +0,-1
?cursor = 0,1
PUSH "B"
?cursor = 0,2
PUSH "\e[3@"
scrollrect 0..1,2..80 => +0,-3
!ICH with DECSLRM
PUSH "\e[?69h"
PUSH "\e[;50s"
PUSH "\e[20G\e[@"
scrollrect 0..1,19..50 => +0,-1
!ICH outside DECSLRM
PUSH "\e[70G\e[@"
# nothing happens
!DCH
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ABBC"
PUSH "\e[3D"
?cursor = 0,1
PUSH "\e[P"
scrollrect 0..1,1..80 => +0,+1
?cursor = 0,1
PUSH "\e[3P"
scrollrect 0..1,1..80 => +0,+3
?cursor = 0,1
!DCH with DECSLRM
PUSH "\e[?69h"
PUSH "\e[;50s"
PUSH "\e[20G\e[P"
scrollrect 0..1,19..50 => +0,+1
!DCH outside DECSLRM
PUSH "\e[70G\e[P"
# nothing happens
!ECH
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ABC"
PUSH "\e[2D"
?cursor = 0,1
PUSH "\e[X"
erase 0..1,1..2
?cursor = 0,1
PUSH "\e[3X"
erase 0..1,1..4
?cursor = 0,1
# ECH more columns than there are should be bounded
PUSH "\e[100X"
erase 0..1,1..80
!IL
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "A\r\nC"
?cursor = 1,1
PUSH "\e[L"
scrollrect 1..25,0..80 => -1,+0
# TODO: ECMA-48 says we should move to line home, but neither xterm nor
# xfce4-terminal do this
?cursor = 1,1
PUSH "\rB"
?cursor = 1,1
PUSH "\e[3L"
scrollrect 1..25,0..80 => -3,+0
!IL with DECSTBM
PUSH "\e[5;15r"
PUSH "\e[5H\e[L"
scrollrect 4..15,0..80 => -1,+0
!IL outside DECSTBM
PUSH "\e[20H\e[L"
# nothing happens
!IL with DECSTBM+DECSLRM
PUSH "\e[?69h"
PUSH "\e[10;50s"
PUSH "\e[5;10H\e[L"
scrollrect 4..15,9..50 => -1,+0
!DL
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "A\r\nB\r\nB\r\nC"
?cursor = 3,1
PUSH "\e[2H"
?cursor = 1,0
PUSH "\e[M"
scrollrect 1..25,0..80 => +1,+0
?cursor = 1,0
PUSH "\e[3M"
scrollrect 1..25,0..80 => +3,+0
?cursor = 1,0
!DL with DECSTBM
PUSH "\e[5;15r"
PUSH "\e[5H\e[M"
scrollrect 4..15,0..80 => +1,+0
!DL outside DECSTBM
PUSH "\e[20H\e[M"
# nothing happens
!DL with DECSTBM+DECSLRM
PUSH "\e[?69h"
PUSH "\e[10;50s"
PUSH "\e[5;10H\e[M"
scrollrect 4..15,9..50 => +1,+0
!DECIC
RESET
erase 0..25,0..80
PUSH "\e[20G\e[5'}"
scrollrect 0..25,19..80 => +0,-5
!DECIC with DECSTBM+DECSLRM
PUSH "\e[?69h"
PUSH "\e[4;20r\e[20;60s"
PUSH "\e[4;20H\e[3'}"
scrollrect 3..20,19..60 => +0,-3
!DECIC outside DECSLRM
PUSH "\e[70G\e['}"
# nothing happens
!DECDC
RESET
erase 0..25,0..80
PUSH "\e[20G\e[5'~"
scrollrect 0..25,19..80 => +0,+5
!DECDC with DECSTBM+DECSLRM
PUSH "\e[?69h"
PUSH "\e[4;20r\e[20;60s"
PUSH "\e[4;20H\e[3'~"
scrollrect 3..20,19..60 => +0,+3
!DECDC outside DECSLRM
PUSH "\e[70G\e['~"
# nothing happens
!EL 0
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ABCDE"
PUSH "\e[3D"
?cursor = 0,2
PUSH "\e[0K"
erase 0..1,2..80
?cursor = 0,2
!EL 1
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ABCDE"
PUSH "\e[3D"
?cursor = 0,2
PUSH "\e[1K"
erase 0..1,0..3
?cursor = 0,2
!EL 2
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ABCDE"
PUSH "\e[3D"
?cursor = 0,2
PUSH "\e[2K"
erase 0..1,0..80
?cursor = 0,2
!SEL
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "\e[11G"
?cursor = 0,10
PUSH "\e[?0K"
erase 0..1,10..80 selective
?cursor = 0,10
PUSH "\e[?1K"
erase 0..1,0..11 selective
?cursor = 0,10
PUSH "\e[?2K"
erase 0..1,0..80 selective
?cursor = 0,10
!ED 0
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "\e[2;2H"
?cursor = 1,1
PUSH "\e[0J"
erase 1..2,1..80
erase 2..25,0..80
?cursor = 1,1
!ED 1
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "\e[2;2H"
?cursor = 1,1
PUSH "\e[1J"
erase 0..1,0..80
erase 1..2,0..2
?cursor = 1,1
!ED 2
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "\e[2;2H"
?cursor = 1,1
PUSH "\e[2J"
erase 0..25,0..80
?cursor = 1,1
!SED
RESET
erase 0..25,0..80
PUSH "\e[5;5H"
?cursor = 4,4
PUSH "\e[?0J"
erase 4..5,4..80 selective
erase 5..25,0..80 selective
?cursor = 4,4
PUSH "\e[?1J"
erase 0..4,0..80 selective
erase 4..5,0..5 selective
?cursor = 4,4
PUSH "\e[?2J"
erase 0..25,0..80 selective
?cursor = 4,4
!DECRQSS on DECSCA
PUSH "\e[2\"q"
PUSH "\eP\$q\"q\e\\"
output "\eP1\$r2\"q\e\\"
WANTSTATE -s+m
!ICH move+erase emuation
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ACD"
PUSH "\e[2D"
?cursor = 0,1
PUSH "\e[@"
moverect 0..1,1..79 -> 0..1,2..80
erase 0..1,1..2
?cursor = 0,1
PUSH "B"
?cursor = 0,2
PUSH "\e[3@"
moverect 0..1,2..77 -> 0..1,5..80
erase 0..1,2..5
!DCH move+erase emulation
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ABBC"
PUSH "\e[3D"
?cursor = 0,1
PUSH "\e[P"
moverect 0..1,2..80 -> 0..1,1..79
erase 0..1,79..80
?cursor = 0,1
PUSH "\e[3P"
moverect 0..1,4..80 -> 0..1,1..77
erase 0..1,77..80
?cursor = 0,1

View File

@@ -0,0 +1,105 @@
INIT
WANTSTATE g
!Default
RESET
PUSH "#"
putglyph 0x23 1 0,0
!Designate G0=UK
RESET
PUSH "\e(A"
PUSH "#"
putglyph 0x00a3 1 0,0
!Designate G0=DEC drawing
RESET
PUSH "\e(0"
PUSH "a"
putglyph 0x2592 1 0,0
!Designate G1 + LS1
RESET
PUSH "\e)0"
PUSH "a"
putglyph 0x61 1 0,0
PUSH "\x0e"
PUSH "a"
putglyph 0x2592 1 0,1
!LS0
PUSH "\x0f"
PUSH "a"
putglyph 0x61 1 0,2
!Designate G2 + LS2
PUSH "\e*0"
PUSH "a"
putglyph 0x61 1 0,3
PUSH "\en"
PUSH "a"
putglyph 0x2592 1 0,4
PUSH "\x0f"
PUSH "a"
putglyph 0x61 1 0,5
!Designate G3 + LS3
PUSH "\e+0"
PUSH "a"
putglyph 0x61 1 0,6
PUSH "\eo"
PUSH "a"
putglyph 0x2592 1 0,7
PUSH "\x0f"
PUSH "a"
putglyph 0x61 1 0,8
!SS2
PUSH "a\x{8e}aa"
putglyph 0x61 1 0,9
putglyph 0x2592 1 0,10
putglyph 0x61 1 0,11
!SS3
PUSH "a\x{8f}aa"
putglyph 0x61 1 0,12
putglyph 0x2592 1 0,13
putglyph 0x61 1 0,14
!LS1R
RESET
PUSH "\e~"
PUSH "\xe1"
putglyph 0x61 1 0,0
PUSH "\e)0"
PUSH "\xe1"
putglyph 0x2592 1 0,1
!LS2R
RESET
PUSH "\e}"
PUSH "\xe1"
putglyph 0x61 1 0,0
PUSH "\e*0"
PUSH "\xe1"
putglyph 0x2592 1 0,1
!LS3R
RESET
PUSH "\e|"
PUSH "\xe1"
putglyph 0x61 1 0,0
PUSH "\e+0"
PUSH "\xe1"
putglyph 0x2592 1 0,1
UTF8 1
!Mixed US-ASCII and UTF-8
# U+0108 == 0xc4 0x88
RESET
PUSH "\e(B"
PUSH "AB\xc4\x88D"
putglyph 0x0041 1 0,0
putglyph 0x0042 1 0,1
putglyph 0x0108 1 0,2
putglyph 0x0044 1 0,3

View File

@@ -0,0 +1,86 @@
INIT
UTF8 1
WANTSTATE gme
!Insert/Replace Mode
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "AC\e[DB"
putglyph 0x41 1 0,0
putglyph 0x43 1 0,1
putglyph 0x42 1 0,1
PUSH "\e[4h"
PUSH "\e[G"
PUSH "AC\e[DB"
moverect 0..1,0..79 -> 0..1,1..80
erase 0..1,0..1
putglyph 0x41 1 0,0
moverect 0..1,1..79 -> 0..1,2..80
erase 0..1,1..2
putglyph 0x43 1 0,1
moverect 0..1,1..79 -> 0..1,2..80
erase 0..1,1..2
putglyph 0x42 1 0,1
!Insert mode only happens once for UTF-8 combining
PUSH "e"
moverect 0..1,2..79 -> 0..1,3..80
erase 0..1,2..3
putglyph 0x65 1 0,2
PUSH "\xCC\x81"
putglyph 0x65,0x301 1 0,2
!Newline/Linefeed mode
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "\e[5G\n"
?cursor = 1,4
PUSH "\e[20h"
PUSH "\e[5G\n"
?cursor = 2,0
!DEC origin mode
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "\e[5;15r"
PUSH "\e[H"
?cursor = 0,0
PUSH "\e[3;3H"
?cursor = 2,2
PUSH "\e[?6h"
PUSH "\e[H"
?cursor = 4,0
PUSH "\e[3;3H"
?cursor = 6,2
!DECRQM on DECOM
PUSH "\e[?6h"
PUSH "\e[?6\$p"
output "\e[?6;1\$y"
PUSH "\e[?6l"
PUSH "\e[?6\$p"
output "\e[?6;2\$y"
!Origin mode with DECSLRM
PUSH "\e[?6h"
PUSH "\e[?69h"
PUSH "\e[20;60s"
PUSH "\e[H"
?cursor = 4,19
PUSH "\e[?69l"
!Origin mode bounds cursor to scrolling region
PUSH "\e[H"
PUSH "\e[10A"
?cursor = 4,0
PUSH "\e[20B"
?cursor = 14,0
!Origin mode without scroll region
PUSH "\e[?6l"
PUSH "\e[r\e[?6h"
?cursor = 0,0

View File

@@ -0,0 +1,48 @@
INIT
WANTSTATE g
!Placement
RESET
PUSH "AB\e[79GCDE"
putglyph 0x41 1 0,0
putglyph 0x42 1 0,1
putglyph 0x43 1 0,78
putglyph 0x44 1 0,79
putglyph 0x45 1 1,0
!Resize
RESET
RESIZE 27,85
PUSH "AB\e[79GCDE"
putglyph 0x41 1 0,0
putglyph 0x42 1 0,1
putglyph 0x43 1 0,78
putglyph 0x44 1 0,79
putglyph 0x45 1 0,80
?cursor = 0,81
!Resize without reset
RESIZE 28,90
?cursor = 0,81
PUSH "FGHI"
putglyph 0x46 1 0,81
putglyph 0x47 1 0,82
putglyph 0x48 1 0,83
putglyph 0x49 1 0,84
?cursor = 0,85
!Resize shrink moves cursor
RESIZE 25,80
?cursor = 0,79
!Resize grow doesn't cancel phantom
RESET
PUSH "\e[79GAB"
putglyph 0x41 1 0,78
putglyph 0x42 1 0,79
?cursor = 0,79
RESIZE 30,100
?cursor = 0,80
PUSH "C"
putglyph 0x43 1 0,80
?cursor = 0,81

View File

@@ -0,0 +1,172 @@
INIT
WANTSTATE p
!DECRQM on with mouse off
PUSH "\e[?1000\$p"
output "\e[?1000;2\$y"
PUSH "\e[?1002\$p"
output "\e[?1002;2\$y"
PUSH "\e[?1003\$p"
output "\e[?1003;2\$y"
!Mouse in simple button report mode
RESET
settermprop 1 true
settermprop 2 true
settermprop 7 1
PUSH "\e[?1000h"
settermprop 8 1
!Press 1
MOUSEMOVE 0,0 0
MOUSEBTN d 1 0
output "\e[M\x20\x21\x21"
!Release 1
MOUSEBTN u 1 0
output "\e[M\x23\x21\x21"
!Ctrl-Press 1
MOUSEBTN d 1 C
output "\e[M\x30\x21\x21"
MOUSEBTN u 1 C
output "\e[M\x33\x21\x21"
!Button 2
MOUSEBTN d 2 0
output "\e[M\x21\x21\x21"
MOUSEBTN u 2 0
output "\e[M\x23\x21\x21"
!Position
MOUSEMOVE 10,20 0
MOUSEBTN d 1 0
output "\e[M\x20\x35\x2b"
MOUSEBTN u 1 0
output "\e[M\x23\x35\x2b"
MOUSEMOVE 10,21 0
# no output
!Wheel events
MOUSEBTN d 4 0
output "\e[M\x60\x36\x2b"
MOUSEBTN d 4 0
output "\e[M\x60\x36\x2b"
MOUSEBTN d 5 0
output "\e[M\x61\x36\x2b"
!DECRQM on mouse button mode
PUSH "\e[?1000\$p"
output "\e[?1000;1\$y"
PUSH "\e[?1002\$p"
output "\e[?1002;2\$y"
PUSH "\e[?1003\$p"
output "\e[?1003;2\$y"
!Drag events
RESET
settermprop 1 true
settermprop 2 true
settermprop 7 1
PUSH "\e[?1002h"
settermprop 8 2
MOUSEMOVE 5,5 0
MOUSEBTN d 1 0
output "\e[M\x20\x26\x26"
MOUSEMOVE 5,6 0
output "\e[M\x40\x27\x26"
MOUSEMOVE 6,6 0
output "\e[M\x40\x27\x27"
MOUSEMOVE 6,6 0
# no output
MOUSEBTN u 1 0
output "\e[M\x23\x27\x27"
MOUSEMOVE 6,7
# no output
!DECRQM on mouse drag mode
PUSH "\e[?1000\$p"
output "\e[?1000;2\$y"
PUSH "\e[?1002\$p"
output "\e[?1002;1\$y"
PUSH "\e[?1003\$p"
output "\e[?1003;2\$y"
!Non-drag motion events
PUSH "\e[?1003h"
settermprop 8 3
MOUSEMOVE 6,8 0
output "\e[M\x43\x29\x27"
!DECRQM on mouse motion mode
PUSH "\e[?1000\$p"
output "\e[?1000;2\$y"
PUSH "\e[?1002\$p"
output "\e[?1002;2\$y"
PUSH "\e[?1003\$p"
output "\e[?1003;1\$y"
!Bounds checking
MOUSEMOVE 300,300 0
output "\e[M\x43\xff\xff"
MOUSEBTN d 1 0
output "\e[M\x20\xff\xff"
MOUSEBTN u 1 0
output "\e[M\x23\xff\xff"
!DECRQM on standard encoding mode
PUSH "\e[?1005\$p"
output "\e[?1005;2\$y"
PUSH "\e[?1006\$p"
output "\e[?1006;2\$y"
PUSH "\e[?1015\$p"
output "\e[?1015;2\$y"
!UTF-8 extended encoding mode
# 300 + 32 + 1 = 333 = U+014d = \xc5\x8d
PUSH "\e[?1005h"
MOUSEBTN d 1 0
output "\e[M\x20\xc5\x8d\xc5\x8d"
MOUSEBTN u 1 0
output "\e[M\x23\xc5\x8d\xc5\x8d"
!DECRQM on UTF-8 extended encoding mode
PUSH "\e[?1005\$p"
output "\e[?1005;1\$y"
PUSH "\e[?1006\$p"
output "\e[?1006;2\$y"
PUSH "\e[?1015\$p"
output "\e[?1015;2\$y"
!SGR extended encoding mode
PUSH "\e[?1006h"
MOUSEBTN d 1 0
output "\e[<0;301;301M"
MOUSEBTN u 1 0
output "\e[<0;301;301m"
!DECRQM on SGR extended encoding mode
PUSH "\e[?1005\$p"
output "\e[?1005;2\$y"
PUSH "\e[?1006\$p"
output "\e[?1006;1\$y"
PUSH "\e[?1015\$p"
output "\e[?1015;2\$y"
!rxvt extended encoding mode
PUSH "\e[?1015h"
MOUSEBTN d 1 0
output "\e[0;301;301M"
MOUSEBTN u 1 0
output "\e[3;301;301M"
!DECRQM on rxvt extended encoding mode
PUSH "\e[?1005\$p"
output "\e[?1005;2\$y"
PUSH "\e[?1006\$p"
output "\e[?1006;2\$y"
PUSH "\e[?1015\$p"
output "\e[?1015;1\$y"

View File

@@ -0,0 +1,36 @@
INIT
WANTSTATE p
RESET
settermprop 1 true
settermprop 2 true
settermprop 7 1
!Cursor visibility
PUSH "\e[?25h"
settermprop 1 true
PUSH "\e[?25\$p"
output "\e[?25;1\$y"
PUSH "\e[?25l"
settermprop 1 false
PUSH "\e[?25\$p"
output "\e[?25;2\$y"
!Cursor blink
PUSH "\e[?12h"
settermprop 2 true
PUSH "\e[?12\$p"
output "\e[?12;1\$y"
PUSH "\e[?12l"
settermprop 2 false
PUSH "\e[?12\$p"
output "\e[?12;2\$y"
!Cursor shape
PUSH "\e[3 q"
settermprop 2 true
settermprop 7 2
!Title
PUSH "\e]2;Here is my title\a"
settermprop 4 "Here is my title"

View File

@@ -0,0 +1,69 @@
INIT
UTF8 1
WANTSTATE gm
!79th Column
PUSH "\e[75G"
PUSH "A"x5
putglyph 0x41 1 0,74
putglyph 0x41 1 0,75
putglyph 0x41 1 0,76
putglyph 0x41 1 0,77
putglyph 0x41 1 0,78
?cursor = 0,79
!80th Column Phantom
PUSH "A"
putglyph 0x41 1 0,79
?cursor = 0,79
!Line Wraparound
PUSH "B"
putglyph 0x42 1 1,0
?cursor = 1,1
!Line Wraparound during combined write
PUSH "\e[78G"
PUSH "BBBCC"
putglyph 0x42 1 1,77
putglyph 0x42 1 1,78
putglyph 0x42 1 1,79
putglyph 0x43 1 2,0
putglyph 0x43 1 2,1
?cursor = 2,2
!DEC Auto Wrap Mode
RESET
PUSH "\e[?7l"
PUSH "\e[75G"
PUSH "D"x6
putglyph 0x44 1 0,74
putglyph 0x44 1 0,75
putglyph 0x44 1 0,76
putglyph 0x44 1 0,77
putglyph 0x44 1 0,78
putglyph 0x44 1 0,79
?cursor = 0,79
PUSH "D"
putglyph 0x44 1 0,79
?cursor = 0,79
PUSH "\e[?7h"
!80th column causes linefeed on wraparound
PUSH "\e[25;78HABC"
putglyph 0x41 1 24,77
putglyph 0x42 1 24,78
putglyph 0x43 1 24,79
?cursor = 24,79
PUSH "D"
moverect 1..25,0..80 -> 0..24,0..80
putglyph 0x44 1 24,0
!80th column phantom linefeed phantom cancelled by explicit cursor move
PUSH "\e[25;78HABC"
putglyph 0x41 1 24,77
putglyph 0x42 1 24,78
putglyph 0x43 1 24,79
?cursor = 24,79
PUSH "\e[25;1HD"
putglyph 0x44 1 24,0

View File

@@ -0,0 +1,60 @@
INIT
WANTSTATE g
!Initial
RESET
PUSH "\tX"
putglyph 0x58 1 0,8
PUSH "\tX"
putglyph 0x58 1 0,16
?cursor = 0,17
!HTS
PUSH "\e[5G\eH"
PUSH "\e[G\tX"
putglyph 0x58 1 0,4
?cursor = 0,5
!TBC 0
PUSH "\e[9G\e[g"
PUSH "\e[G\tX\tX"
putglyph 0x58 1 0,4
putglyph 0x58 1 0,16
?cursor = 0,17
!TBC 3
PUSH "\e[3g\e[50G\eH\e[G"
?cursor = 0,0
PUSH "\tX"
putglyph 0x58 1 0,49
?cursor = 0,50
!Tabstops after resize
RESET
RESIZE 30,100
# Should be 100/8 = 12 tabstops
PUSH "\tX"
putglyph 0x58 1 0,8
PUSH "\tX"
putglyph 0x58 1 0,16
PUSH "\tX"
putglyph 0x58 1 0,24
PUSH "\tX"
putglyph 0x58 1 0,32
PUSH "\tX"
putglyph 0x58 1 0,40
PUSH "\tX"
putglyph 0x58 1 0,48
PUSH "\tX"
putglyph 0x58 1 0,56
PUSH "\tX"
putglyph 0x58 1 0,64
PUSH "\tX"
putglyph 0x58 1 0,72
PUSH "\tX"
putglyph 0x58 1 0,80
PUSH "\tX"
putglyph 0x58 1 0,88
PUSH "\tX"
putglyph 0x58 1 0,96
?cursor = 0,97

View File

@@ -0,0 +1,64 @@
INIT
WANTSTATE p
RESET
settermprop 1 true
settermprop 2 true
settermprop 7 1
!Set up state
PUSH "\e[2;2H"
?cursor = 1,1
PUSH "\e[1m"
?pen bold = on
!Save
PUSH "\e[?1048h"
!Change state
PUSH "\e[5;5H"
?cursor = 4,4
PUSH "\e[4 q"
settermprop 2 false
settermprop 7 2
PUSH "\e[22;4m"
?pen bold = off
?pen underline = 1
!Restore
PUSH "\e[?1048l"
settermprop 1 true
settermprop 2 true
settermprop 7 1
?cursor = 1,1
?pen bold = on
?pen underline = 0
!Save/restore using DECSC/DECRC
PUSH "\e[2;2H\e7"
?cursor = 1,1
PUSH "\e[5;5H"
?cursor = 4,4
PUSH "\e8"
settermprop 1 true
settermprop 2 true
settermprop 7 1
?cursor = 1,1
!Save twice, restore twice happens on both edge transitions
PUSH "\e[2;10H\e[?1048h\e[6;10H\e[?1048h"
PUSH "\e[H"
?cursor = 0,0
PUSH "\e[?1048l"
settermprop 1 true
settermprop 2 true
settermprop 7 1
?cursor = 5,9
PUSH "\e[H"
?cursor = 0,0
PUSH "\e[?1048l"
settermprop 1 true
settermprop 2 true
settermprop 7 1
?cursor = 5,9

View File

@@ -0,0 +1,132 @@
INIT
WANTSTATE
!Unmodified ASCII
INCHAR 0 41
output "A"
INCHAR 0 61
output "a"
!Ctrl modifier on ASCII letters
INCHAR C 41
output "\e[65;5u"
INCHAR C 61
output "\x01"
!Alt modifier on ASCII letters
INCHAR A 41
output "\eA"
INCHAR A 61
output "\ea"
!Ctrl-Alt modifier on ASCII letters
INCHAR CA 41
output "\e[65;7u"
INCHAR CA 61
output "\e\x01"
!Special handling of Ctrl-I
INCHAR 0 49
output "I"
INCHAR 0 69
output "i"
INCHAR C 49
output "\e[73;5u"
INCHAR C 69
output "\e[105;5u"
INCHAR A 49
output "\eI"
INCHAR A 69
output "\ei"
INCHAR CA 49
output "\e[73;7u"
INCHAR CA 69
output "\e[105;7u"
!Special handling of Space
INCHAR 0 20
output " "
INCHAR S 20
output "\e[32;2u"
INCHAR C 20
output "\0"
INCHAR SC 20
output "\e[32;6u"
INCHAR A 20
output "\e "
INCHAR SA 20
output "\e[32;4u"
INCHAR CA 20
output "\e\0"
INCHAR SCA 20
output "\e[32;8u"
!Cursor keys in reset (cursor) mode
INKEY 0 Up
output "\e[A"
INKEY S Up
output "\e[1;2A"
INKEY C Up
output "\e[1;5A"
INKEY SC Up
output "\e[1;6A"
INKEY A Up
output "\e[1;3A"
INKEY SA Up
output "\e[1;4A"
INKEY CA Up
output "\e[1;7A"
INKEY SCA Up
output "\e[1;8A"
!Cursor keys in application mode
PUSH "\e[?1h"
# Plain "Up" should be SS3 A now
INKEY 0 Up
output "\eOA"
# Modified keys should still use CSI
INKEY S Up
output "\e[1;2A"
INKEY C Up
output "\e[1;5A"
!Shift-Tab should be different
INKEY 0 Tab
output "\x09"
INKEY S Tab
output "\e[Z"
INKEY C Tab
output "\e[9;5u"
INKEY A Tab
output "\e\x09"
INKEY CA Tab
output "\e[9;7u"
!Enter in linefeed mode
INKEY 0 Enter
output "\x0d"
!Enter in newline mode
PUSH "\e[20h"
INKEY 0 Enter
output "\x0d\x0a"
!Keypad in DECKPNM
INKEY 0 KP0
output "0"
!Keypad in DECKPAM
PUSH "\e="
INKEY 0 KP0
output "\eOp"
!Bracketed paste mode off
PASTE START
PASTE END
!Bracketed paste mode on
PUSH "\e[?2004h"
PASTE START
output "\e[200~"
PASTE END
output "\e[201~"

View File

@@ -0,0 +1,62 @@
INIT
WANTSTATE
!DA
RESET
PUSH "\e[c"
output "\e[?1;2c"
!DSR
RESET
PUSH "\e[5n"
output "\e[0n"
!CPR
PUSH "\e[6n"
output "\e[1;1R"
PUSH "\e[10;10H\e[6n"
output "\e[10;10R"
!DECCPR
PUSH "\e[?6n"
output "\e[?10;10R"
!DECRQSS on DECSCUSR
PUSH "\e[3 q"
PUSH "\eP\$q q\e\\"
output "\eP1\$r3 q\e\\"
!DECRQSS on SGR
PUSH "\e[1;5;7m"
PUSH "\eP\$qm\e\\"
output "\eP1\$r1;5;7m\e\\"
!DECRQSS on SGR ANSI colours
PUSH "\e[0;31;42m"
PUSH "\eP\$qm\e\\"
output "\eP1\$r31;42m\e\\"
!DECRQSS on SGR ANSI hi-bright colours
PUSH "\e[0;93;104m"
PUSH "\eP\$qm\e\\"
output "\eP1\$r93;104m\e\\"
!DECRQSS on SGR 256-palette colours
PUSH "\e[0;38:5:56;48:5:78m"
PUSH "\eP\$qm\e\\"
output "\eP1\$r38:5:56;48:5:78m\e\\"
!DECRQSS on SGR RGB8 colours
PUSH "\e[0;38:2:24:68:112;48:2:13:57:101m"
PUSH "\eP\$qm\e\\"
output "\eP1\$r38:2:24:68:112;48:2:13:57:101m\e\\"
!S8C1T on DSR
PUSH "\e G"
PUSH "\e[5n"
output "\x{9b}0n"
PUSH "\e F"
!Truncation on attempted buffer overflow
PUSH "\e[6n" x 20
output "\e[10;10R" x 7

View File

@@ -0,0 +1,32 @@
INIT
WANTSTATE
RESET
!RIS homes cursor
PUSH "\e[5;5H"
?cursor = 4,4
WANTSTATE +m
PUSH "\ec"
?cursor = 0,0
WANTSTATE -m
!RIS cancels scrolling region
PUSH "\e[5;10r"
WANTSTATE +s
PUSH "\ec\e[25H\n"
scrollrect 0..25,0..80 => +1,+0
WANTSTATE -s
!RIS erases screen
PUSH "ABCDE"
WANTSTATE +e
PUSH "\ec"
erase 0..25,0..80
WANTSTATE -e
!RIS clears tabstops
PUSH "\e[5G\eH\e[G\t"
?cursor = 0,4
PUSH "\ec\t"
?cursor = 0,8

View File

@@ -0,0 +1,61 @@
INIT
WANTSTATE g
!Single Width, Single Height
RESET
PUSH "\e#5"
PUSH "Hello"
putglyph 0x48 1 0,0
putglyph 0x65 1 0,1
putglyph 0x6c 1 0,2
putglyph 0x6c 1 0,3
putglyph 0x6f 1 0,4
!Double Width, Single Height
RESET
PUSH "\e#6"
PUSH "Hello"
putglyph 0x48 1 0,0 dwl
putglyph 0x65 1 0,1 dwl
putglyph 0x6c 1 0,2 dwl
putglyph 0x6c 1 0,3 dwl
putglyph 0x6f 1 0,4 dwl
?cursor = 0,5
PUSH "\e[40GAB"
putglyph 0x41 1 0,39 dwl
putglyph 0x42 1 1,0
?cursor = 1,1
!Double Height
RESET
PUSH "\e#3"
PUSH "Hello"
putglyph 0x48 1 0,0 dwl dhl-top
putglyph 0x65 1 0,1 dwl dhl-top
putglyph 0x6c 1 0,2 dwl dhl-top
putglyph 0x6c 1 0,3 dwl dhl-top
putglyph 0x6f 1 0,4 dwl dhl-top
?cursor = 0,5
PUSH "\r\n\e#4"
PUSH "Hello"
putglyph 0x48 1 1,0 dwl dhl-bottom
putglyph 0x65 1 1,1 dwl dhl-bottom
putglyph 0x6c 1 1,2 dwl dhl-bottom
putglyph 0x6c 1 1,3 dwl dhl-bottom
putglyph 0x6f 1 1,4 dwl dhl-bottom
?cursor = 1,5
!Double Width scrolling
RESET
PUSH "\e[20H\e#6ABC"
putglyph 0x41 1 19,0 dwl
putglyph 0x42 1 19,1 dwl
putglyph 0x43 1 19,2 dwl
PUSH "\e[25H\n"
PUSH "\e[19;4HDE"
putglyph 0x44 1 18,3 dwl
putglyph 0x45 1 18,4 dwl
PUSH "\e[H\eM"
PUSH "\e[20;6HFG"
putglyph 0x46 1 19,5 dwl
putglyph 0x47 1 19,6 dwl

View File

@@ -0,0 +1,19 @@
INIT
WANTSTATE f
RESET
!Unrecognised control
PUSH "\x03"
control 03
!Unrecognised CSI
PUSH "\e[?15;2z"
csi 0x7a L=3f 15,2
!Unrecognised OSC
PUSH "\e]27;Something\e\\"
osc "27;Something"
!Unrecognised DCS
PUSH "\ePz123\e\\"
dcs "z123"

Some files were not shown because too many files have changed in this diff Show More