├── .gitignore ├── .gitmodules ├── FAQ ├── HACKING ├── Makefile.am ├── README ├── THANKS ├── build-aux ├── .gitignore ├── mkdotzee.lua └── run-tests.lua ├── configure.ac ├── luarocks-config.lua.in ├── m4 ├── .gitignore └── ax_lua.m4 ├── mkrockspecs.lua ├── rockspecs.lua ├── tests ├── Makefile.am ├── describe-thing_1.lua ├── describe-thing_1.output ├── describe-thing_2.lua ├── describe-thing_2.output ├── edit-copy.lua ├── edit-copy.output ├── edit-cut.lua ├── edit-cut.output ├── edit-delete-horizontal-space.lua ├── edit-delete-horizontal-space.output ├── edit-delete-next-character.lua ├── edit-delete-next-character.output ├── edit-delete-previous-character.lua ├── edit-delete-previous-character.output ├── edit-delete-word-backward.lua ├── edit-delete-word-backward.output ├── edit-delete-word.lua ├── edit-delete-word.output ├── edit-indent-relative.lua ├── edit-indent-relative.output ├── edit-indent.lua ├── edit-indent.output ├── edit-insert-character.lua ├── edit-insert-character.output ├── edit-insert-newline-and-indent.lua ├── edit-insert-newline-and-indent.output ├── edit-insert-newline.lua ├── edit-insert-newline.output ├── edit-paste.lua ├── edit-paste.output ├── edit-revert.lua ├── edit-revert.output ├── edit-select-other-end.lua ├── edit-select-other-end.output ├── edit-shell-command.lua ├── edit-shell-command.output ├── edit-undo.lua ├── edit-undo.output ├── edit-undo_2.lua ├── edit-undo_2.output ├── fixed-screen │ ├── move-next-page.lua │ ├── move-next-page.output │ ├── move-previous-page.lua │ └── move-previous-page.output ├── goal-column.lua ├── goal-column.output ├── help-key.lua ├── help-key.output ├── interactive │ ├── describe-thing_1.lua │ ├── describe-thing_1.output │ ├── describe-thing_2.lua │ ├── describe-thing_2.output │ ├── edit-copy.lua │ ├── edit-copy.output │ ├── edit-cut.lua │ ├── edit-cut.output │ ├── edit-delete-horizontal-space.lua │ ├── edit-delete-horizontal-space.output │ ├── edit-delete-next-character.lua │ ├── edit-delete-next-character.output │ ├── edit-delete-previous-character.lua │ ├── edit-delete-previous-character.output │ ├── edit-delete-word-backward.lua │ ├── edit-delete-word-backward.output │ ├── edit-delete-word.lua │ ├── edit-delete-word.output │ ├── edit-find-backward.lua │ ├── edit-find-backward.output │ ├── edit-find.lua │ ├── edit-find.output │ ├── edit-goto-column.lua │ ├── edit-goto-column.output │ ├── edit-goto-line.lua │ ├── edit-goto-line.output │ ├── edit-indent.lua │ ├── edit-indent.output │ ├── edit-insert-newline-and-indent.lua │ ├── edit-insert-newline-and-indent.output │ ├── edit-insert-newline.lua │ ├── edit-insert-newline.output │ ├── edit-insert-quoted.lua │ ├── edit-insert-quoted.output │ ├── edit-paste.lua │ ├── edit-paste.output │ ├── edit-replace.lua │ ├── edit-replace.output │ ├── edit-revert.lua │ ├── edit-revert.output │ ├── edit-select-other-end.lua │ ├── edit-select-other-end.output │ ├── edit-shell-command.lua │ ├── edit-shell-command.output │ ├── edit-undo.lua │ ├── edit-undo.output │ ├── execute-command.lua │ ├── execute-command.output │ ├── goal-column.lua │ ├── goal-column.output │ ├── help-key.lua │ ├── help-key.output │ ├── macro-play.lua │ ├── macro-play.output │ ├── move-end-file.lua │ ├── move-end-file.output │ ├── move-end-line.lua │ ├── move-end-line.output │ ├── move-next-character.lua │ ├── move-next-character.output │ ├── move-next-line.lua │ ├── move-next-line.output │ ├── move-next-paragraph.lua │ ├── move-next-paragraph.output │ ├── move-next-word.lua │ ├── move-next-word.output │ ├── move-previous-character.lua │ ├── move-previous-character.output │ ├── move-previous-line.lua │ ├── move-previous-line.output │ ├── move-previous-paragraph.lua │ ├── move-previous-paragraph.output │ ├── move-previous-word.lua │ ├── move-previous-word.output │ ├── move-start-file.lua │ ├── move-start-file.output │ ├── move-start-line.lua │ ├── move-start-line.output │ ├── preferences-set-variable.lua │ ├── preferences-set-variable.output │ ├── resume_search.lua │ └── resume_search.output ├── move-end-file.lua ├── move-end-file.output ├── move-end-line.lua ├── move-end-line.output ├── move-goto-character.lua ├── move-goto-character.output ├── move-goto-column.lua ├── move-goto-column.output ├── move-goto-line.lua ├── move-goto-line.output ├── move-next-character.lua ├── move-next-character.output ├── move-next-line.lua ├── move-next-line.output ├── move-next-paragraph.lua ├── move-next-paragraph.output ├── move-next-word.lua ├── move-next-word.output ├── move-previous-character.lua ├── move-previous-character.output ├── move-previous-line.lua ├── move-previous-line.output ├── move-previous-paragraph.lua ├── move-previous-paragraph.output ├── move-previous-word.lua ├── move-previous-word.output ├── move-start-file.lua ├── move-start-file.output ├── move-start-line.lua ├── move-start-line.output ├── preferences-set-variable.lua ├── preferences-set-variable.output ├── preferences-set-variable_nonexistent_variable.lua ├── preferences-set-variable_nonexistent_variable.output ├── regression │ ├── 33910_execute-kbd-macro_with_edit-insert-quoted.lua │ ├── 33910_execute-kbd-macro_with_edit-insert-quoted.output │ ├── 34086_call-last-kbd-macro.lua │ ├── 34086_call-last-kbd-macro.output │ ├── 34087_undo_macro.lua │ ├── 34087_undo_macro.output │ ├── 34193_interactive_insert.lua │ ├── 34193_interactive_insert.output │ ├── 35562_search-backward.lua │ ├── 35562_search-backward.output │ ├── 35567_minibuffer_ding_non_printable.lua │ ├── 35567_minibuffer_ding_non_printable.output │ ├── forward-char_at_end.lua │ └── forward-char_at_end.output └── test.input ├── zee-git-1.rockspec └── zee ├── .gitignore ├── astr.lua ├── bind.lua ├── buffer.lua ├── completion.lua ├── cua_bindings.lua ├── cut.lua ├── edit.lua ├── emacs_bindings.lua ├── eval.lua ├── file.lua ├── getkey.lua ├── help.lua ├── init.lua.in ├── keycode.lua ├── macro.lua ├── main.lua ├── minibuf.lua ├── move.lua ├── search.lua ├── shell.lua ├── term.lua ├── term_curses.lua ├── undo.lua ├── variables.lua └── zee.in /.gitignore: -------------------------------------------------------------------------------- 1 | /zee-[0-9]*.rock 2 | /zee-[0-9]*.rockspec 3 | *~ 4 | /COPYING 5 | /ChangeLog 6 | /INSTALL 7 | /README-release 8 | /aclocal.m4 9 | /autom4te.cache 10 | /config.cache 11 | /config.log 12 | /config.status 13 | /config.status.lineno 14 | /configure 15 | /configure.lineno 16 | /luarocks 17 | /luarocks-config.lua 18 | /release-notes* 19 | /zee*.tar.gz 20 | Makefile 21 | Makefile.in 22 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "gnulib"] 2 | path = gnulib 3 | url = git://git.sv.gnu.org/gnulib 4 | -------------------------------------------------------------------------------- /FAQ: -------------------------------------------------------------------------------- 1 | Zee FAQ - Frequently Asked Questions 2 | 3 | Copyright (c) 1997-2012 Free Software Foundation, Inc. 4 | 5 | Copying and distribution of this file, with or without 6 | modification, are permitted in any medium without royalty 7 | provided the copyright notice and this notice are preserved. 8 | 9 | ------------------------------------------------------------------------------ 10 | 11 | INDEX 12 | 13 | 1 Functionality 14 | 1.1 Some keys don't work (e.g. `C-h' does backspace). 15 | 1.2 The META/ALT key doesn't work in xterm. 16 | 1.3 How do I handle non-ASCII characters? 17 | 18 | 2 General questions 19 | 2.1 What does `Zee' mean? 20 | 2.2 Does Zee support Unicode/UTF-8? 21 | 22 | ------------------------------------------------------------------------------ 23 | 24 | 1 Functionality 25 | 26 | 1.1 Some keys don't work (e.g. `C-h' does backspace). 27 | 28 | The terminfo entry for your terminal type is probably incorrect. 29 | Rebuilding Zee against the latest ncurses may help. 30 | 31 | With Mac OS X, Terminal.app outputs different escape sequences 32 | than described by the xterm-color terminfo entry. Make sure you 33 | have the default terminal type preference set to xterm-256color, 34 | or else run Zee with: 35 | 36 | TERM=xterm-256color zee 37 | 38 | 1.2 The META/ALT key doesn't work in xterm. 39 | 40 | This is probably because you are using "8-bit input". 41 | Using the following X resources should make things work: 42 | 43 | XTerm*eightBitInput: false 44 | UXTerm*eightBitInput: false 45 | 46 | Typically you'll want to put these lines in your ~/.Xresources 47 | file. 48 | 49 | 1.3 How do I handle non-ASCII characters? 50 | 51 | Zee uses the operating system's locale support, so you need to 52 | set an appropriate locale; how you do this depends on your OS. 53 | However, Zee only works with 8-bit locales. 54 | 55 | ------------------------------------------------------------------------------ 56 | 57 | 2 General questions 58 | 59 | 2.1 What does `Zee' mean? 60 | 61 | It's a short name related to `Zile', the name of the editor from 62 | which Zee is descended. 63 | 64 | 2.2 Does Zee support Unicode/UTF-8? 65 | 66 | No, but this is planned. 67 | -------------------------------------------------------------------------------- /HACKING: -------------------------------------------------------------------------------- 1 | Zee developers' notes 2 | --------------------- 3 | 4 | Copyright (c) 2011-2014 Free Software Foundation, Inc. 5 | 6 | Copying and distribution of this file, with or without 7 | modification, are permitted in any medium without royalty 8 | provided the copyright notice and this notice are preserved. 9 | 10 | 11 | Coding style 12 | ------------ 13 | 14 | Rather than attempt an exhaustive list, the following points address 15 | just FDQs (Frequently Discussed Questions). 16 | 17 | 0. Follow the style of existing code. Consistency is more important 18 | than any particular element of style. 19 | 20 | 1. Avoid reversed comparisons. Arguably a good idea in C, but in Lua 21 | "if a = 0 then..." is a syntax error, so there's no need to inflict 22 | "if 0 == a then..." on those who don't like that style. 23 | 24 | 2. Put space around operators and variables: "for i = 0, #t", not 25 | "for i=0,#t". The latter is cramped and harder to read. 26 | 27 | 3. Use one-line conditionals sparingly. As a rule of thumb, only use 28 | them when the entire line is shorter than 70 characters. Their use is 29 | encouraged in code of the form "if CONDITION then return end", and a 30 | one-line "if...then...else...end" may often be superior to the 31 | quasi-ternary operator "x and a or b" (where if "a" can be false 32 | results in "b"). 33 | 34 | 35 | Making a release 36 | ---------------- 37 | 38 | To make a release you need woger, from 39 | http://rrt.sc3d.org/Software/woger and the dependencies it lists for 40 | releasing on Github and Freecode. 41 | 42 | * Write the release notes in release-notes-$VERSION 43 | 44 | * Run: 45 | 46 | make release 47 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Top-level Makefile.am 2 | # 3 | # Copyright (c) 1997-2016 Free Software Foundation, Inc. 4 | # 5 | # This file is part of Zee. 6 | # 7 | # This program is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 3, or (at your option) 10 | # any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | CLOC = cloc --force-lang=lua,in 21 | 22 | ACLOCAL_AMFLAGS = -I m4 23 | 24 | LUA_PATH ?= ; 25 | LUA_ENV = LUA_PATH_5_3="$(abs_srcdir)/?.lua;$(abs_srcdir)/?/init.lua;$(LUA_PATH_5_3)" 26 | 27 | doc_DATA = FAQ 28 | 29 | BUILT_SOURCES = \ 30 | $(PACKAGE)/init.lua \ 31 | $(PACKAGE)/$(PACKAGE).in 32 | 33 | bin_SCRIPTS = $(PACKAGE)/$(PACKAGE) 34 | 35 | LUA_RUNTIME = \ 36 | $(PACKAGE)/astr.lua \ 37 | $(PACKAGE)/eval.lua \ 38 | $(PACKAGE)/main.lua \ 39 | $(PACKAGE)/variables.lua \ 40 | $(PACKAGE)/move.lua \ 41 | $(PACKAGE)/buffer.lua \ 42 | $(PACKAGE)/completion.lua \ 43 | $(PACKAGE)/shell.lua \ 44 | $(PACKAGE)/getkey.lua \ 45 | $(PACKAGE)/help.lua \ 46 | $(PACKAGE)/file.lua \ 47 | $(PACKAGE)/cut.lua \ 48 | $(PACKAGE)/edit.lua \ 49 | $(PACKAGE)/macro.lua \ 50 | $(PACKAGE)/minibuf.lua \ 51 | $(PACKAGE)/search.lua \ 52 | $(PACKAGE)/undo.lua \ 53 | $(PACKAGE)/term.lua \ 54 | $(PACKAGE)/keycode.lua \ 55 | $(PACKAGE)/bind.lua \ 56 | $(PACKAGE)/cua_bindings.lua \ 57 | $(PACKAGE)/term_curses.lua 58 | 59 | pkgdata_DATA = $(PACKAGE)/init.lua \ 60 | $(LUA_RUNTIME) \ 61 | $(PACKAGE)/emacs_bindings.lua 62 | 63 | PRODUCTIONSOURCES = \ 64 | $(LUA_RUNTIME) \ 65 | $(PACKAGE)/$(PACKAGE).in \ 66 | $(PACKAGE)/init.lua.in \ 67 | tests/Makefile.am \ 68 | Makefile.am \ 69 | configure.ac 70 | 71 | $(PACKAGE)/init.lua: Makefile.am $(PACKAGE)/init.lua.in 72 | cat $(PACKAGE)/init.lua.in > $@ 73 | for i in $(LUA_RUNTIME); do echo 'require ("'`echo $$i | sed -e 's|\\.lua$$||'`'")' >> $@; done 74 | 75 | install-data-hook: 76 | PACKAGE="$(PACKAGE)" PACKAGE_NAME="$(PACKAGE_NAME)" $(LUA_ENV) $(LUA) $(DESTDIR)$(bindir)/$(PACKAGE) --no-init-file --eval "loadfile ('$(srcdir)/build-aux/mkdot$(PACKAGE).lua') ()" > $@.tmp 77 | $(INSTALL_DATA) $@.tmp $(DESTDIR)$(pkgdatadir)/dot$(PACKAGE).sample 78 | rm -f $@.tmp 79 | 80 | include tests/Makefile.am 81 | 82 | loc: 83 | $(CLOC) $(PRODUCTIONSOURCES) $(srcdir)/build-aux/mkdot$(PACKAGE).lua $(srcdir)/mkrockspecs.lua $(srcdir)/rockspecs.lua 84 | 85 | loc-tests: 86 | $(CLOC) $(ALL_TESTS) $(srcdir)/build-aux/run-tests.lua 87 | 88 | rockspecs: 89 | rm -f *.rockspec 90 | $(LUA) mkrockspecs.lua $(PACKAGE) $(VERSION) 91 | $(LUA) mkrockspecs.lua $(PACKAGE) git 92 | 93 | release: rockspecs 94 | git diff --exit-code && \ 95 | git push && \ 96 | git tag -a -m "Release tag" v$(VERSION) && \ 97 | git push --tags && \ 98 | LUAROCKS_CONFIG=$(abs_srcdir)/luarocks-config.lua luarocks --tree=$(abs_srcdir)/luarocks build $(PACKAGE)-$(VERSION)-1.rockspec && \ 99 | woger luarocks package=$(PACKAGE) version=$(VERSION) 100 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Zee 2 | === 3 | 4 | Zee is free software, licensed under the GNU GPL. 5 | 6 | Copyright (c) 1997-2016 Free Software Foundation, Inc. 7 | 8 | **Copying and distribution of this file, with or without modification, 9 | are permitted in any medium without royalty provided the copyright 10 | notice and this notice are preserved.** 11 | 12 | 13 | INTRODUCTION 14 | ============ 15 | 16 | Zee is a lightweight editor. Zee is aimed at small footprint systems 17 | and quick editing sessions (it starts up and shuts down instantly). 18 | Zee's home page is at: 19 | 20 | > 21 | 22 | Zee is written in Lua 5.3 using POSIX APIs, and requires these 23 | additional modules: 24 | 25 | * Lua stdlib 26 | * lrexlib 27 | (the rex_gnu module must be built) 28 | * luaposix 29 | (the curses module must be built) 30 | * alien 31 | 32 | For the exact versions required, see `rockspecs.lua`. 33 | 34 | 35 | INSTALLING 36 | ========== 37 | 38 | The simplest way to install the latest release of Zee is to use 39 | [Luarocks][] 40 | 41 | [Luarocks]: http://luarocks.org/ 42 | 43 | Run: 44 | 45 | luarocks install zee 46 | 47 | Development sources are available from the web page. You can build the 48 | latest development sources with: 49 | 50 | luarocks build https://github.com/rrthomas/zee/raw/master/zee-git-1.rockspec 51 | 52 | 53 | REPORTING BUGS 54 | ============== 55 | 56 | If Zee doesn't work for you, before you report the problem, please try 57 | upgrading to the latest released version first, to see whether your 58 | issue has been fixed already. If you can, please also check whether 59 | the latest development sources still exhibit the problem. 60 | 61 | Please file bug reports in the issue tracker at the home page (see 62 | above). 63 | 64 | If you're not an experienced bug reporter, please read this before 65 | reporting a bug: 66 | 67 | > 68 | 69 | Zee has a suite of tests in the source distribution, which you can run 70 | with: 71 | 72 | make check 73 | 74 | If, when you report a bug, you can create a similar test that 75 | demonstrates it, the maintainers will be most grateful, and it will 76 | prevent them from accidentally reintroducing the bug in a subsequent 77 | release. 78 | 79 | 80 | RELATED WORK 81 | ============ 82 | 83 | [Zim][http://zim-wiki.org/] 84 | [Leo][http://webpages.charter.net/edreamleo/front.html] 85 | -------------------------------------------------------------------------------- /THANKS: -------------------------------------------------------------------------------- 1 | The Zee maintainers would like to thank all those who worked on GNU 2 | Zile, from which Zee is derived. 3 | 4 | In particular: 5 | 6 | * Gary Vaughan contributed to the Lua version of Zile, 7 | from which Zee was directly adapted. 8 | 9 | * Alistair Turnbull contributed to the C version 10 | of Zee, from which code was directly translated for Lua Zee. 11 | -------------------------------------------------------------------------------- /build-aux/.gitignore: -------------------------------------------------------------------------------- 1 | /announce-gen 2 | /config.guess 3 | /config.sub 4 | /do-release-commit-and-tag 5 | /install-sh 6 | /gendocs.sh 7 | /gitlog-to-changelog 8 | /gnu-web-doc-update 9 | /gnupload 10 | /missing 11 | /useless-if-before-free 12 | /vc-list-files 13 | /update-copyright 14 | -------------------------------------------------------------------------------- /build-aux/mkdotzee.lua: -------------------------------------------------------------------------------- 1 | -- Produce dotzee.sample 2 | -- 3 | -- Copyright (c) 2012-2014 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | -- This script should be run as zee -e "loadfile ('script.lua') ()" 21 | 22 | -- Don't note where the contents of this file comes from or that it's 23 | -- auto-generated, because it's ugly in a user configuration file. 24 | io.write ( 25 | [[ 26 | -- ]] .. os.getenv ("PACKAGE_NAME") .. [[ configuration 27 | 28 | -- Rebind keys with: 29 | -- bind_key("key", "func") 30 | 31 | ]]) 32 | 33 | for name, var in pairs (env) do 34 | if not command_exists (name) then 35 | io.writelines ("-- " .. var.doc:gsub ("\n", "\n; "), 36 | "-- Default value is " .. var.val .. ".", 37 | "call_command (\"preferences-set-variable\", \"" .. name .. "\", \"" .. var.val .. "\")", 38 | "") 39 | end 40 | end 41 | 42 | os.exit () 43 | -------------------------------------------------------------------------------- /build-aux/run-tests.lua: -------------------------------------------------------------------------------- 1 | -- run-tests 2 | -- 3 | -- Copyright (c) 2010-2015 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | posix = require "posix" 21 | std = require "std".barrel () 22 | 23 | -- N.B. Tests that use macro-play must note that keyboard input 24 | -- is only evaluated once the script has finished running. 25 | 26 | -- The following are defined in the environment for a build 27 | local srcdir = os.getenv ("srcdir") or "." 28 | local abs_srcdir = os.getenv ("abs_srcdir") or "." 29 | local builddir = os.getenv ("builddir") or "." 30 | 31 | local pass = 0 32 | local fail = 0 33 | 34 | local editor_cmd = std.io.catfile (builddir, "zee", os.getenv ("PACKAGE")) 35 | local srcdir_pat = string.escape_pattern (srcdir) 36 | 37 | function run_test (test, name, edit_file, cmd, args) 38 | posix.spawn {"cp", io.catfile (srcdir, "tests", "test.input"), edit_file} 39 | posix.spawn {"chmod", "+w", edit_file} 40 | local status = posix.spawn {cmd, table.unpack (args)} 41 | if status == 0 then 42 | if posix.spawn {"diff", test .. ".output", edit_file} == 0 then 43 | posix.spawn {"rm", "-f", edit_file, edit_file .. "~"} 44 | return true 45 | else 46 | std.debug (name .. " failed to produce correct output") 47 | end 48 | else 49 | std.debug (name .. " failed to run with error code " .. tostring (status)) 50 | end 51 | end 52 | 53 | for _, name in ipairs (arg) do 54 | local test = name:gsub ("%.lua$", "") 55 | if io.open (test .. ".output") ~= nil then 56 | name = test:gsub (io.catfile (srcdir, "tests/"), "") 57 | local edit_file = test:gsub ("^" .. srcdir_pat, builddir) .. ".input" 58 | local args = {"--no-init-file", edit_file, "--eval", ("loadfile('%s.lua') ()"):format (test:gsub ("^" .. srcdir_pat, abs_srcdir))} 59 | 60 | posix.spawn {"mkdir", "-p", posix.dirname (edit_file)} 61 | 62 | if run_test (test, name, edit_file, editor_cmd, args) then 63 | pass = pass + 1 64 | else 65 | fail = fail + 1 66 | end 67 | end 68 | end 69 | 70 | posix.spawn {"tset"} 71 | std.debug (string.format ("%d pass(es) and %d failure(s)", pass, fail)) 72 | 73 | os.exit (fail) 74 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl configure.ac 2 | dnl 3 | dnl Copyright (c) 1997-2016 Free Software Foundation, Inc. 4 | dnl 5 | dnl This file is part of Zee. 6 | dnl 7 | dnl This program is free software; you can redistribute it and/or modify 8 | dnl it under the terms of the GNU General Public License as published 9 | dnl by the Free Software Foundation; either version 3, or (at your 10 | dnl option) any later version. 11 | dnl 12 | dnl This program is distributed in the hope that it will be useful, but 13 | dnl WITHOUT ANY WARRANTY; without even the implied warranty of 14 | dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | dnl General Public License for more details. 16 | dnl 17 | dnl You should have received a copy of the GNU General Public License 18 | dnl along with this program. If not, see . 19 | 20 | AC_PREREQ([2.61]) 21 | 22 | dnl Initialise autoconf and automake 23 | AC_INIT([Zee], [0.7.2], [https://github.com/rrthomas/zee]) 24 | AC_CONFIG_AUX_DIR([build-aux]) 25 | AM_INIT_AUTOMAKE([-Wall -Werror std-options foreign silent-rules]) 26 | 27 | dnl Lua 28 | AX_PROG_LUA 29 | 30 | dnl Generate output 31 | AC_CONFIG_FILES([Makefile zee/zee luarocks-config.lua], [chmod +x zee/zee]) 32 | AC_OUTPUT 33 | -------------------------------------------------------------------------------- /luarocks-config.lua.in: -------------------------------------------------------------------------------- 1 | rocks_trees = { 2 | "@abs_srcdir@/luarocks" 3 | } 4 | -------------------------------------------------------------------------------- /m4/.gitignore: -------------------------------------------------------------------------------- 1 | /00gnulib.m4 2 | /gnulib-cache.m4 3 | /gnulib-common.m4 4 | /gnulib-comp.m4 5 | /gnulib-tool.m4 6 | /onceonly.m4 7 | -------------------------------------------------------------------------------- /mkrockspecs.lua: -------------------------------------------------------------------------------- 1 | -- Generate rockspecs from a prototype with variants 2 | 3 | local table = require "std.table" 4 | local tree = require "std.tree" 5 | 6 | if select ("#", ...) < 2 then 7 | io.stderr:write "Usage: mkrockspecs PACKAGE VERSION\n" 8 | os.exit () 9 | end 10 | 11 | package_name = select (1, ...) 12 | version = select (2, ...) 13 | 14 | function format (x, indent) 15 | indent = indent or "" 16 | if type (x) == "table" then 17 | local s = "{\n" 18 | for i, v in ipairs (table.sort (table.keys (x))) do 19 | if type (v) ~= "number" then 20 | s = s..indent..v.." = "..format (x[v], indent.." ")..",\n" 21 | end 22 | end 23 | for i, v in ipairs (x) do 24 | s = s..indent..format (v, indent.." ")..",\n" 25 | end 26 | return s..indent:sub (1, -3).."}" 27 | elseif type (x) == "string" then 28 | return string.format ("%q", x) 29 | else 30 | return tostring (x) 31 | end 32 | end 33 | 34 | flavour = "" -- a global, visible in loadfile 35 | for f, spec in pairs (loadfile ("rockspecs.lua") ()) do 36 | if f ~= "default" then 37 | local specfile = package_name.."-"..(f ~= "" and f:lower ().."-" or "")..version.."-1.rockspec" 38 | h = io.open (specfile, "w") 39 | assert (h) 40 | flavour = f 41 | local specs = loadfile ("rockspecs.lua") () -- reload to get current flavour interpolated 42 | local spec = tree.merge (tree (specs.default), tree (specs[f])) 43 | local s = "" 44 | for i, v in ipairs (table.sort (table.keys (spec))) do 45 | s = s..v.." = "..format (spec[v], " ").."\n" 46 | end 47 | h:write (s) 48 | h:close () 49 | os.execute ("luarocks lint " .. specfile) 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /rockspecs.lua: -------------------------------------------------------------------------------- 1 | -- Rockspec data 2 | 3 | -- Variables to be interpolated: 4 | -- 5 | -- package_name 6 | -- version 7 | 8 | local default = { 9 | package = package_name, 10 | version = version.."-1", 11 | source = { 12 | url = "git://github.com/rrthomas/"..package_name..".git", 13 | }, 14 | description = { 15 | summary = "Experimental lightweight editor", 16 | detailed = [[ 17 | Zee is a lightweight editor. Zee is aimed at small footprint 18 | systems and quick editing sessions (it starts up and shuts down 19 | instantly).]], 20 | homepage = "http://github.com/rrthomas/"..package_name.."/", 21 | license = "GPLv3+", 22 | }, 23 | dependencies = { 24 | "lua == 5.3", 25 | "stdlib >= 41.2.0", 26 | "luaposix == 33.3.1", -- FIXME: Fix to use lcurses package 27 | "lrexlib-gnu >= 2.8.0", 28 | "alien >= 0.7.1", 29 | }, 30 | build = { 31 | type = "command", 32 | build_command = "LUA=$(LUA) autoreconf -i && ./configure --prefix=$(PREFIX) --libdir=$(LIBDIR) --datadir=$(LUADIR) && make clean && make", 33 | install_command = "make install", 34 | copy_directories = {}, 35 | }, 36 | } 37 | 38 | if version ~= "git" then 39 | default.source.branch = "v"..version 40 | end 41 | 42 | return {default=default, [""]={}} 43 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | # Tests Makefile.am 2 | # 3 | # Copyright (c) 1997-2014 Free Software Foundation, Inc. 4 | # 5 | # This file is part of Zee. 6 | # 7 | # This program is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 3, or (at your option) 10 | # any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | RUNTESTS = $(LUA) $(srcdir)/build-aux/run-tests.lua 21 | 22 | TERM ?= vt100 23 | 24 | # FIXME: Make interactive tests look up keybindings so they are resistant to default bindings changing 25 | TESTS_NORMAL = \ 26 | $(srcdir)/tests/*.lua \ 27 | $(srcdir)/tests/interactive/*.lua \ 28 | $(srcdir)/tests/regression/*.lua 29 | 30 | TESTS_FIXED_SCREEN = \ 31 | $(srcdir)/tests/fixed-screen/*.lua 32 | 33 | TEST_OUTPUTS = \ 34 | $(srcdir)/tests/*.output \ 35 | $(srcdir)/tests/interactive/*.output \ 36 | $(srcdir)/tests/regression/*.output \ 37 | $(srcdir)/tests/fixed-screen/*.output 38 | 39 | ALL_TESTS = \ 40 | $(TESTS_NORMAL) \ 41 | $(TESTS_FIXED_SCREEN) 42 | 43 | TESTS_ENVIRONMENT = \ 44 | abs_srcdir=$(abs_srcdir) \ 45 | srcdir=$(srcdir) \ 46 | abs_builddir=$(abs_builddir) \ 47 | PACKAGE=$(PACKAGE) \ 48 | TERM=$(TERM) 49 | 50 | # Use to find which test hangs: 51 | check-debug: 52 | $(LUA_ENV) $(TESTS_ENVIRONMENT) $(RUNTESTS) $(TESTS_NORMAL) > /dev/null 53 | 54 | # FIXME: nproc and xargs --max-procs are GNU-specific 55 | check-local: $(builddir)/zee/zee 56 | COLUMNS=80 LINES=24 $(TESTS_ENVIRONMENT) $(RUNTESTS) $(TESTS_FIXED_SCREEN) > /dev/null 57 | NPROC=`nproc`; \ 58 | echo $(TESTS_NORMAL) | $(LUA_ENV) $(TESTS_ENVIRONMENT) xargs --max-procs=$$NPROC --max-args=$$(( `echo $(TESTS_NORMAL) | wc -w` / $$NPROC + 1 )) $(RUNTESTS) > /dev/null 59 | -------------------------------------------------------------------------------- /tests/describe-thing_1.lua: -------------------------------------------------------------------------------- 1 | call_command ("help-thing", "move-next-character") 2 | call_command ("file-save") 3 | call_command ("file-quit") 4 | -------------------------------------------------------------------------------- /tests/describe-thing_1.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/describe-thing_2.lua: -------------------------------------------------------------------------------- 1 | call_command ("help-thing", "tab-width") 2 | call_command ("file-save") 3 | call_command ("file-quit") 4 | -------------------------------------------------------------------------------- /tests/describe-thing_2.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-copy.lua: -------------------------------------------------------------------------------- 1 | call_command ("edit-select-on") 2 | call_command ("move-next-character") 3 | call_command ("move-next-character") 4 | call_command ("move-next-character") 5 | call_command ("move-next-character") 6 | call_command ("edit-copy") 7 | call_command ("edit-paste") 8 | call_command ("file-save") 9 | call_command ("file-quit") 10 | -------------------------------------------------------------------------------- /tests/edit-copy.output: -------------------------------------------------------------------------------- 1 | HereHere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-cut.lua: -------------------------------------------------------------------------------- 1 | call_command ("edit-select-on") 2 | call_command ("move-next-line") 3 | call_command ("move-next-line") 4 | call_command ("edit-cut") 5 | call_command ("file-save") 6 | call_command ("file-quit") 7 | -------------------------------------------------------------------------------- /tests/edit-cut.output: -------------------------------------------------------------------------------- 1 | 2 | And more than one paragraph. 3 | -------------------------------------------------------------------------------- /tests/edit-delete-horizontal-space.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-next-character") 2 | call_command ("move-next-character") 3 | call_command ("move-next-character") 4 | call_command ("move-next-character") 5 | call_command ("edit-delete-horizontal-space") 6 | call_command ("file-save") 7 | call_command ("file-quit") 8 | -------------------------------------------------------------------------------- /tests/edit-delete-horizontal-space.output: -------------------------------------------------------------------------------- 1 | Hereis a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-delete-next-character.lua: -------------------------------------------------------------------------------- 1 | call_command ("edit-delete-next-character") 2 | call_command ("file-save") 3 | call_command ("file-quit") 4 | -------------------------------------------------------------------------------- /tests/edit-delete-next-character.output: -------------------------------------------------------------------------------- 1 | ere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-delete-previous-character.lua: -------------------------------------------------------------------------------- 1 | insert_string ("aa") 2 | call_command ("edit-delete-previous-character") 3 | call_command ("file-save") 4 | call_command ("file-quit") 5 | -------------------------------------------------------------------------------- /tests/edit-delete-previous-character.output: -------------------------------------------------------------------------------- 1 | aHere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-delete-word-backward.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-end-line") 2 | call_command ("edit-delete-word-backward") 3 | call_command ("file-save") 4 | call_command ("file-quit") 5 | -------------------------------------------------------------------------------- /tests/edit-delete-word-backward.output: -------------------------------------------------------------------------------- 1 | Here is a sample 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-delete-word.lua: -------------------------------------------------------------------------------- 1 | call_command ("edit-delete-word") 2 | call_command ("edit-delete-word") 3 | call_command ("edit-delete-word") 4 | call_command ("file-save") 5 | call_command ("file-quit") 6 | -------------------------------------------------------------------------------- /tests/edit-delete-word.output: -------------------------------------------------------------------------------- 1 | sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-indent-relative.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-next-line") 2 | call_command ("move-next-line") 3 | call_command ("edit-indent-relative") 4 | insert_string ("f") 5 | call_command ("edit-indent-relative") 6 | insert_string ("fffff") 7 | call_command ("edit-indent-relative") 8 | insert_string ("aaa") 9 | call_command ("file-save") 10 | call_command ("file-quit") 11 | -------------------------------------------------------------------------------- /tests/edit-indent-relative.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | f fffff aaa 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-indent.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-next-line") 2 | call_command ("move-next-line") 3 | call_command ("edit-indent") 4 | call_command ("edit-indent") 5 | insert_string ("tab") 6 | call_command ("file-save") 7 | call_command ("file-quit") 8 | -------------------------------------------------------------------------------- /tests/edit-indent.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | tab 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-insert-character.lua: -------------------------------------------------------------------------------- 1 | insert_string ("a") 2 | call_command ("file-save") 3 | call_command ("file-quit") 4 | -------------------------------------------------------------------------------- /tests/edit-insert-character.output: -------------------------------------------------------------------------------- 1 | aHere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-insert-newline-and-indent.lua: -------------------------------------------------------------------------------- 1 | call_command ("edit-insert-newline-and-indent") 2 | call_command ("move-next-line") 3 | call_command ("edit-insert-newline-and-indent") 4 | call_command ("move-next-line") 5 | call_command ("edit-insert-newline-and-indent") 6 | call_command ("edit-insert-newline-and-indent") 7 | call_command ("file-save") 8 | call_command ("file-quit") 9 | -------------------------------------------------------------------------------- /tests/edit-insert-newline-and-indent.output: -------------------------------------------------------------------------------- 1 | 2 | Here is a sample file. 3 | 4 | It has several lines. 5 | 6 | 7 | 8 | And more than one paragraph. 9 | -------------------------------------------------------------------------------- /tests/edit-insert-newline.lua: -------------------------------------------------------------------------------- 1 | call_command ("edit-insert-newline") 2 | call_command ("edit-insert-newline") 3 | call_command ("edit-insert-newline") 4 | insert_string ("a") 5 | call_command ("file-save") 6 | call_command ("file-quit") 7 | -------------------------------------------------------------------------------- /tests/edit-insert-newline.output: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | aHere is a sample file. 5 | It has several lines. 6 | 7 | And more than one paragraph. 8 | -------------------------------------------------------------------------------- /tests/edit-paste.lua: -------------------------------------------------------------------------------- 1 | call_command ("edit-select-on") 2 | call_command ("move-next-line") 3 | call_command ("move-next-line") 4 | call_command ("edit-cut") 5 | call_command ("move-next-line") 6 | call_command ("move-next-line") 7 | call_command ("move-next-line") 8 | call_command ("edit-paste") 9 | call_command ("file-save") 10 | call_command ("file-quit") 11 | -------------------------------------------------------------------------------- /tests/edit-paste.output: -------------------------------------------------------------------------------- 1 | 2 | And more than one paragraph. 3 | Here is a sample file. 4 | It has several lines. 5 | -------------------------------------------------------------------------------- /tests/edit-revert.lua: -------------------------------------------------------------------------------- 1 | call_command ("edit-delete-next-character") 2 | call_command ("edit-delete-next-character") 3 | call_command ("edit-delete-next-character") 4 | call_command ("edit-delete-next-character") 5 | call_command ("edit-revert") 6 | call_command ("file-save") 7 | call_command ("file-quit") 8 | -------------------------------------------------------------------------------- /tests/edit-revert.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-select-other-end.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-next-character") 2 | call_command ("move-next-character") 3 | call_command ("move-next-character") 4 | call_command ("move-next-character") 5 | call_command ("edit-select-on") 6 | call_command ("forward-line") 7 | call_command ("forward-line") 8 | call_command ("edit-select-other-end") 9 | insert_string ("f") 10 | call_command ("file-save") 11 | call_command ("file-quit") 12 | -------------------------------------------------------------------------------- /tests/edit-select-other-end.output: -------------------------------------------------------------------------------- 1 | Heref is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-shell-command.lua: -------------------------------------------------------------------------------- 1 | call_command ("edit-select-on") 2 | call_command ("move-next-line") 3 | call_command ("move-next-line") 4 | call_command ("move-next-line") 5 | call_command ("move-next-line") 6 | call_command ("edit-shell-command", "sort") 7 | call_command ("file-save") 8 | call_command ("file-quit") 9 | -------------------------------------------------------------------------------- /tests/edit-shell-command.output: -------------------------------------------------------------------------------- 1 | 2 | And more than one paragraph. 3 | Here is a sample file. 4 | It has several lines. 5 | -------------------------------------------------------------------------------- /tests/edit-undo.lua: -------------------------------------------------------------------------------- 1 | call_command ("edit-delete-next-character") 2 | call_command ("edit-delete-next-character") 3 | call_command ("edit-delete-next-character") 4 | call_command ("edit-delete-next-character") 5 | call_command ("edit-undo") 6 | call_command ("edit-undo") 7 | call_command ("edit-undo") 8 | call_command ("file-save") 9 | call_command ("file-quit") 10 | -------------------------------------------------------------------------------- /tests/edit-undo.output: -------------------------------------------------------------------------------- 1 | ere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/edit-undo_2.lua: -------------------------------------------------------------------------------- 1 | call_command ("edit-insert-character", "a") 2 | call_command ("edit-undo") 3 | call_command ("edit-insert-character", "b") 4 | call_command ("file-save") 5 | call_command ("file-quit") 6 | -------------------------------------------------------------------------------- /tests/edit-undo_2.output: -------------------------------------------------------------------------------- 1 | bHere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/fixed-screen/move-next-page.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-next-page") 2 | insert_string ("a") 3 | call_command ("file-save") 4 | call_command ("file-quit") 5 | -------------------------------------------------------------------------------- /tests/fixed-screen/move-next-page.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | a -------------------------------------------------------------------------------- /tests/fixed-screen/move-previous-page.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-end-file") 2 | call_command ("move-previous-page") 3 | insert_string ("a") 4 | call_command ("file-save") 5 | call_command ("file-quit") 6 | -------------------------------------------------------------------------------- /tests/fixed-screen/move-previous-page.output: -------------------------------------------------------------------------------- 1 | aHere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/goal-column.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-next-character") 2 | call_command ("move-next-character") 3 | call_command ("move-next-character") 4 | call_command ("move-next-character") 5 | call_command ("move-next-line") 6 | call_command ("move-next-line") 7 | call_command ("move-next-line") 8 | insert_string ("a") 9 | call_command ("file-save") 10 | call_command ("file-quit") 11 | -------------------------------------------------------------------------------- /tests/goal-column.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And amore than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/help-key.lua: -------------------------------------------------------------------------------- 1 | call_command ("help-key", "Ctrl-f") 2 | call_command ("file-save") 3 | call_command ("file-quit") 4 | -------------------------------------------------------------------------------- /tests/help-key.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/describe-thing_1.lua: -------------------------------------------------------------------------------- 1 | -- help-thing "move-next-character" Return 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-Alt-x", "h", "e", "l", "p", "-", "t", "h", "i", "n", "g", "Return", "m", "o", "v", "e", "-", "n", "e", "x", "t", "-", "c", "h", "a", "r", "a", "c", "t", "e", "r", "Return", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/describe-thing_1.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/describe-thing_2.lua: -------------------------------------------------------------------------------- 1 | -- help-thing "tab-width" Return 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-Alt-x", "h", "e", "l", "p", "-", "t", "h", "i", "n", "g", "Return", "i", "n", "d", "e", "n", "t", "-", "w", "i", "d", "t", "h", "Return", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/describe-thing_2.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-copy.lua: -------------------------------------------------------------------------------- 1 | -- edit-select-on move-next-character move-next-character move-next-character move-next-character 2 | -- edit-copy edit-paste file-save file-quit 3 | call_command ("macro-play", "Ctrl-@", "Right", "Right", "Right", "Right", "Ctrl-c", "Ctrl-v", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/edit-copy.output: -------------------------------------------------------------------------------- 1 | HereHere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-cut.lua: -------------------------------------------------------------------------------- 1 | -- edit-select-on edit-goto-line 3 Return edit-cut 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-@", "Ctrl-Alt-g", "3", "Return", "Ctrl-x", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/edit-cut.output: -------------------------------------------------------------------------------- 1 | 2 | And more than one paragraph. 3 | -------------------------------------------------------------------------------- /tests/interactive/edit-delete-horizontal-space.lua: -------------------------------------------------------------------------------- 1 | -- move-next-character move-next-character move-next-character move-next-character delete-horizontal-space 2 | -- file-save file-quit 3 | call_command ("macro-play", "Right", "Right", "Right", "Right", "Ctrl-Alt-d", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/edit-delete-horizontal-space.output: -------------------------------------------------------------------------------- 1 | Hereis a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-delete-next-character.lua: -------------------------------------------------------------------------------- 1 | -- edit-delete-next-character file-save file-quit 2 | call_command ("macro-play", "Delete", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/edit-delete-next-character.output: -------------------------------------------------------------------------------- 1 | ere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-delete-previous-character.lua: -------------------------------------------------------------------------------- 1 | -- a a edit-delete-previous-character file-save file-quit 2 | call_command ("macro-play", "a", "a", "Ctrl-?", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/edit-delete-previous-character.output: -------------------------------------------------------------------------------- 1 | aHere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-delete-word-backward.lua: -------------------------------------------------------------------------------- 1 | -- move-end-line edit-kill-word-backward file-save file-quit 2 | call_command ("macro-play", "End", "Ctrl-Alt-?", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/edit-delete-word-backward.output: -------------------------------------------------------------------------------- 1 | Here is a sample 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-delete-word.lua: -------------------------------------------------------------------------------- 1 | -- edit-kill-word edit-kill-word edit-kill-word file-save file-quit 2 | call_command ("macro-play", "Ctrl-Delete", "Ctrl-Delete", "Ctrl-Delete", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/edit-delete-word.output: -------------------------------------------------------------------------------- 1 | sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-find-backward.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-next-line") 2 | call_command ("move-next-line") 3 | -- edit-find-backward e . e Return f file-save file-quit 4 | call_command ("macro-play", "Ctrl-Alt-f", "e", ".", "e", "Return", "f", "Ctrl-s", "Ctrl-q") 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-find-backward.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has sfeveral lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-find.lua: -------------------------------------------------------------------------------- 1 | -- edit-find [ a ] . p Return f file-save file-quit 2 | call_command ("macro-play", "Ctrl-f", "[", "a", "]", ".", "p", "Return", "f", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/edit-find.output: -------------------------------------------------------------------------------- 1 | Here is a sampfle file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-goto-column.lua: -------------------------------------------------------------------------------- 1 | -- edit-goto-column 8 Return a file-save file-quit 2 | call_command ("macro-play", "Ctrl-Alt-c", "8", "Return", "a", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/edit-goto-column.output: -------------------------------------------------------------------------------- 1 | Here isa a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-goto-line.lua: -------------------------------------------------------------------------------- 1 | -- edit-goto-line 4 Return a file-save file-quit 2 | call_command ("macro-play", "Ctrl-Alt-g", "4", "Return", "a", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/edit-goto-line.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | aAnd more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-indent.lua: -------------------------------------------------------------------------------- 1 | -- edit-goto-line 3 Return edit-indent edit-indent t a b 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-Alt-g", "3", "Return", "Alt-Tab", "Alt-Tab", "t", "a", "b", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/edit-indent.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | tab 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-insert-newline-and-indent.lua: -------------------------------------------------------------------------------- 1 | -- edit-insert-newline-and-indent edit-goto-line 3 Return 2 | -- edit-insert-newline-and-indent edit-goto-line 5 Return 3 | -- edit-insert-newline-and-indent edit-insert-newline-and-indent file-save file-quit 4 | call_command ("macro-play", "Return", "Ctrl-Alt-g", "3", "Return", "Return", "Ctrl-Alt-g", "5", "Return", "Return", "Return", "Ctrl-s", "Ctrl-q") 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-insert-newline-and-indent.output: -------------------------------------------------------------------------------- 1 | 2 | Here is a sample file. 3 | 4 | It has several lines. 5 | 6 | 7 | 8 | And more than one paragraph. 9 | -------------------------------------------------------------------------------- /tests/interactive/edit-insert-newline.lua: -------------------------------------------------------------------------------- 1 | -- edit-insert-newline edit-insert-newline edit-insert-newline a file-save file-quit 2 | call_command ("macro-play", "Return", "Return", "Return", "a", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/edit-insert-newline.output: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | aHere is a sample file. 5 | It has several lines. 6 | 7 | And more than one paragraph. 8 | -------------------------------------------------------------------------------- /tests/interactive/edit-insert-quoted.lua: -------------------------------------------------------------------------------- 1 | -- edit-insert-quoted Ctrl-a edit-insert-quoted Ctrl-h edit-insert-quoted Ctrl-z edit-insert-quoted Ctrl-q 2 | -- edit-insert-quoted ESC O P edit-insert-quoted Tab file-save file-quit 3 | call_command ("macro-play", "Ctrl-Alt-q", "Ctrl-a", "Ctrl-Alt-q", "Ctrl-h", "Ctrl-Alt-q", "Ctrl-z", "Ctrl-Alt-q", "Ctrl-q", "Ctrl-Alt-q", "Escape", "O", "P", "Ctrl-Alt-q", "Tab", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/edit-insert-quoted.output: -------------------------------------------------------------------------------- 1 | OP Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-paste.lua: -------------------------------------------------------------------------------- 1 | -- edit-select-on edit-goto-line 3 Return edit-cut move-end-file edit-paste 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-@", "Ctrl-Alt-g", "3", "Return", "Ctrl-x", "Ctrl-End", "Ctrl-v", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/edit-paste.output: -------------------------------------------------------------------------------- 1 | 2 | And more than one paragraph. 3 | Here is a sample file. 4 | It has several lines. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-replace.lua: -------------------------------------------------------------------------------- 1 | -- query-replace l e Return b d Return ! file-save file-quit 2 | call_command ("macro-play", "Ctrl-r", "l", "e", "Return", "b", "d", "Return", "!", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/edit-replace.output: -------------------------------------------------------------------------------- 1 | Here is a sampbd fibd. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-revert.lua: -------------------------------------------------------------------------------- 1 | -- edit-delete-next-character edit-delete-next-character edit-delete-next-character edit-delete-next-character 2 | -- Alt-x edit-revert Return 3 | -- file-save file-quit 4 | call_command ("macro-play", "Delete", "Delete", "Delete", "Delete", "Ctrl-Alt-x", "e", "d", "i", "t", "-", "r", "e", "v", "e", "r", "t", "Return", "Ctrl-s", "Ctrl-q") 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-revert.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-select-other-end.lua: -------------------------------------------------------------------------------- 1 | -- move-next-character move-next-character move-next-character move-next-character 2 | -- edit-select-toggle move-end-file edit-select-other-end f file-save file-quit 3 | call_command ("macro-play", "Right", "Right", "Right", "Right", "Ctrl-@", "Ctrl-End", "Alt-Space", "f", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/edit-select-other-end.output: -------------------------------------------------------------------------------- 1 | Heref is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-shell-command.lua: -------------------------------------------------------------------------------- 1 | -- edit-select-on edit-goto-line 5 Return shell-command-on-region "sort" Return 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-@", "Ctrl-Alt-g", "5", "Return", "Ctrl-Alt-s", "s", "o", "r", "t", "Return", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/edit-shell-command.output: -------------------------------------------------------------------------------- 1 | 2 | And more than one paragraph. 3 | Here is a sample file. 4 | It has several lines. 5 | -------------------------------------------------------------------------------- /tests/interactive/edit-undo.lua: -------------------------------------------------------------------------------- 1 | -- edit-delete-next-character edit-delete-next-character edit-delete-next-character edit-delete-next-character edit-undo edit-undo edit-undo 2 | -- file-save file-quit 3 | call_command ("macro-play", "Delete", "Delete", "Delete", "Delete", "Ctrl-z", "Ctrl-z", "Ctrl-z", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/edit-undo.output: -------------------------------------------------------------------------------- 1 | ere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/execute-command.lua: -------------------------------------------------------------------------------- 1 | -- Alt-x move-next-character Return a file-save file-quit 2 | call_command ("macro-play", "Ctrl-Alt-x", "m", "o", "v", "e", "-", "n", "e", "x", "t", "-", "c", "h", "a", "r", "a", "c", "t", "e", "r", "Return", "a", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/execute-command.output: -------------------------------------------------------------------------------- 1 | Haere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/goal-column.lua: -------------------------------------------------------------------------------- 1 | -- move-next-character move-next-character move-next-character move-next-character 2 | -- move-next-line move-next-line move-next-line a file-save file-quit 3 | call_command ("macro-play", "Right", "Right", "Right", "Right", "Down", "Down", "Down", "a", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/goal-column.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And amore than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/help-key.lua: -------------------------------------------------------------------------------- 1 | -- help-key Ctrl-f 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-Alt-x", "h", "e", "l", "p", "-", "k", "e", "y", "Return", "Right", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/help-key.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/macro-play.lua: -------------------------------------------------------------------------------- 1 | -- macro-record move-next-word a macro-stop call-last-kbd-macro 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-Alt-x", "m", "a", "c", "r", "o", "-", "r", "e", "c", "o", "r", "d", "Return", "Ctrl-Right", "a", "Ctrl-Alt-x", "m", "a", "c", "r", "o", "-", "s", "t", "o", "p", "Return", "Alt-Return", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/macro-play.output: -------------------------------------------------------------------------------- 1 | Herea isa a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/move-end-file.lua: -------------------------------------------------------------------------------- 1 | -- move-end-file a file-save file-quit 2 | call_command ("macro-play", "Ctrl-End", "a", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/move-end-file.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | a -------------------------------------------------------------------------------- /tests/interactive/move-end-line.lua: -------------------------------------------------------------------------------- 1 | -- move-end-line a file-save file-quit 2 | call_command ("macro-play", "End", "a", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/move-end-line.output: -------------------------------------------------------------------------------- 1 | Here is a sample file.a 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/move-next-character.lua: -------------------------------------------------------------------------------- 1 | -- move-next-character move-next-character edit-delete-next-character file-save file-quit 2 | call_command ("macro-play", "Right", "Right", "Delete", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/move-next-character.output: -------------------------------------------------------------------------------- 1 | Hee is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/move-next-line.lua: -------------------------------------------------------------------------------- 1 | -- move-next-line move-next-line a file-save file-quit 2 | call_command ("macro-play", "Down", "Down", "a", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/move-next-line.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | a 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/move-next-paragraph.lua: -------------------------------------------------------------------------------- 1 | -- move-next-paragraph a file-save file-quit 2 | call_command ("macro-play", "Alt-]", "a", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/move-next-paragraph.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | a 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/move-next-word.lua: -------------------------------------------------------------------------------- 1 | -- move-next-word move-next-word move-next-word move-next-word a file-save file-quit 2 | call_command ("macro-play", "Ctrl-Right", "Ctrl-Right", "Ctrl-Right", "Ctrl-Right", "a", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/move-next-word.output: -------------------------------------------------------------------------------- 1 | Here is a samplea file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/move-previous-character.lua: -------------------------------------------------------------------------------- 1 | -- move-end-line move-previous-character move-previous-character edit-delete-previous-character 2 | -- file-save file-quit 3 | call_command ("macro-play", "End", "Left", "Left", "Ctrl-?", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/move-previous-character.output: -------------------------------------------------------------------------------- 1 | Here is a sample fie. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/move-previous-line.lua: -------------------------------------------------------------------------------- 1 | -- move-end-file move-previous-line move-previous-line move-previous-line a file-save file-quit 2 | call_command ("macro-play", "Ctrl-End", "Up", "Up", "Up", "a", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/move-previous-line.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | aIt has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/move-previous-paragraph.lua: -------------------------------------------------------------------------------- 1 | -- move-end-file move-previous-paragraph a file-save file-quit 2 | call_command ("macro-play", "Ctrl-End", "Alt-[", "a", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/move-previous-paragraph.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | a 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/move-previous-word.lua: -------------------------------------------------------------------------------- 1 | -- move-end-line move-previous-word move-previous-word a file-save file-quit 2 | call_command ("macro-play", "End", "Ctrl-Left", "Ctrl-Left", "a", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/move-previous-word.output: -------------------------------------------------------------------------------- 1 | Here is a asample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/move-start-file.lua: -------------------------------------------------------------------------------- 1 | -- move-end-file a move-start-file b file-save file-quit 2 | call_command ("macro-play", "Ctrl-End", "a", "Ctrl-Home", "b", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/interactive/move-start-file.output: -------------------------------------------------------------------------------- 1 | bHere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | a -------------------------------------------------------------------------------- /tests/interactive/move-start-line.lua: -------------------------------------------------------------------------------- 1 | -- edit-goto-line 2 Return move-next-word move-next-word move-next-word move-start-line a 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-Alt-g", "2", "Return", "Ctrl-Right", "Ctrl-Right", "Ctrl-Right", "Home", "a", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/move-start-line.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | aIt has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/preferences-set-variable.lua: -------------------------------------------------------------------------------- 1 | -- preferences-set-variable "case-fold-search" Return false Return 2 | -- edit-find "I" Return a file-save file-quit 3 | call_command ("macro-play", "Ctrl-Alt-x", "p", "r", "e", "f", "e", "r", "e", "n", "c", "e", "s", "-", "s", "e", "t", "-", "v", "a", "r", "i", "a", "b", "l", "e", "Return", "c", "a", "s", "e", "l", "e", "s", "s", "-", "s", "e", "a", "r", "c", "h", "Return", "f", "a", "l", "s", "e", "Return", "Ctrl-f", "I", "Return", "a", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/preferences-set-variable.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | Iat has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/interactive/resume_search.lua: -------------------------------------------------------------------------------- 1 | -- search-forward "ra" isearch-forward ENTER 2 isearch-forward isearch-forward ENTER 3 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-f", "r", "a", "Ctrl-f", "Return", "2", "Ctrl-f", "Ctrl-f", "Return", "3", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/interactive/resume_search.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one para2gra3ph. 5 | -------------------------------------------------------------------------------- /tests/move-end-file.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-end-file") 2 | insert_string ("a") 3 | call_command ("file-save") 4 | call_command ("file-quit") 5 | -------------------------------------------------------------------------------- /tests/move-end-file.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | a -------------------------------------------------------------------------------- /tests/move-end-line.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-end-line") 2 | insert_string ("a") 3 | call_command ("file-save") 4 | call_command ("file-quit") 5 | -------------------------------------------------------------------------------- /tests/move-end-line.output: -------------------------------------------------------------------------------- 1 | Here is a sample file.a 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/move-goto-character.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-goto-character", 40) 2 | insert_string ("fff") 3 | call_command ("file-save") 4 | call_command ("file-quit") 5 | -------------------------------------------------------------------------------- /tests/move-goto-character.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lfffines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/move-goto-column.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-goto-column", 8) 2 | insert_string ("a") 3 | call_command ("file-save") 4 | call_command ("file-quit") 5 | -------------------------------------------------------------------------------- /tests/move-goto-column.output: -------------------------------------------------------------------------------- 1 | Here isa a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/move-goto-line.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-goto-line", "4") 2 | insert_string ("a") 3 | call_command ("file-save") 4 | call_command ("file-quit") 5 | -------------------------------------------------------------------------------- /tests/move-goto-line.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | aAnd more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/move-next-character.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-next-character") 2 | call_command ("move-next-character") 3 | call_command ("edit-delete-next-character") 4 | call_command ("file-save") 5 | call_command ("file-quit") 6 | -------------------------------------------------------------------------------- /tests/move-next-character.output: -------------------------------------------------------------------------------- 1 | Hee is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/move-next-line.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-next-line") 2 | call_command ("move-next-line") 3 | call_command ("move-next-line") 4 | insert_string ("a") 5 | call_command ("file-save") 6 | call_command ("file-quit") 7 | -------------------------------------------------------------------------------- /tests/move-next-line.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | aAnd more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/move-next-paragraph.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-next-paragraph") 2 | insert_string ("a") 3 | call_command ("file-save") 4 | call_command ("file-quit") 5 | -------------------------------------------------------------------------------- /tests/move-next-paragraph.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | a 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/move-next-word.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-next-word") 2 | call_command ("move-next-word") 3 | call_command ("move-next-word") 4 | call_command ("move-next-word") 5 | insert_string ("a") 6 | call_command ("file-save") 7 | call_command ("file-quit") 8 | -------------------------------------------------------------------------------- /tests/move-next-word.output: -------------------------------------------------------------------------------- 1 | Here is a samplea file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/move-previous-character.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-end-line") 2 | call_command ("move-previous-character") 3 | call_command ("move-previous-character") 4 | call_command ("edit-delete-previous-character") 5 | call_command ("file-save") 6 | call_command ("file-quit") 7 | -------------------------------------------------------------------------------- /tests/move-previous-character.output: -------------------------------------------------------------------------------- 1 | Here is a sample fie. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/move-previous-line.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-end-file") 2 | call_command ("move-previous-line") 3 | call_command ("move-previous-line") 4 | call_command ("move-previous-line") 5 | insert_string ("a") 6 | call_command ("file-save") 7 | call_command ("file-quit") 8 | -------------------------------------------------------------------------------- /tests/move-previous-line.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | aIt has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/move-previous-paragraph.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-end-file") 2 | call_command ("move-previous-paragraph") 3 | insert_string ("a") 4 | call_command ("file-save") 5 | call_command ("file-quit") 6 | -------------------------------------------------------------------------------- /tests/move-previous-paragraph.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | a 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/move-previous-word.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-end-line") 2 | call_command ("move-previous-word") 3 | call_command ("move-previous-word") 4 | insert_string ("a") 5 | call_command ("file-save") 6 | call_command ("file-quit") 7 | -------------------------------------------------------------------------------- /tests/move-previous-word.output: -------------------------------------------------------------------------------- 1 | Here is a asample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/move-start-file.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-end-file") 2 | insert_string ("a") 3 | call_command ("move-start-file") 4 | insert_string ("b") 5 | call_command ("file-save") 6 | call_command ("file-quit") 7 | -------------------------------------------------------------------------------- /tests/move-start-file.output: -------------------------------------------------------------------------------- 1 | bHere is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | a -------------------------------------------------------------------------------- /tests/move-start-line.lua: -------------------------------------------------------------------------------- 1 | call_command ("move-next-line") 2 | call_command ("move-next-word") 3 | call_command ("move-next-word") 4 | call_command ("move-next-word") 5 | call_command ("move-start-line") 6 | insert_string ("a") 7 | call_command ("file-save") 8 | call_command ("file-quit") 9 | -------------------------------------------------------------------------------- /tests/move-start-line.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | aIt has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/preferences-set-variable.lua: -------------------------------------------------------------------------------- 1 | call_command ("preferences-set-variable", "caseless-search", false) 2 | execute_command ("edit-find", "I") 3 | insert_string ("a") 4 | call_command ("file-save") 5 | call_command ("file-quit") 6 | -------------------------------------------------------------------------------- /tests/preferences-set-variable.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | Iat has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/preferences-set-variable_nonexistent_variable.lua: -------------------------------------------------------------------------------- 1 | call_command ("preferences-set-variable", "unknown-variable", true) 2 | call_command ("file-save") 3 | call_command ("file-quit") 4 | -------------------------------------------------------------------------------- /tests/preferences-set-variable_nonexistent_variable.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/regression/33910_execute-kbd-macro_with_edit-insert-quoted.lua: -------------------------------------------------------------------------------- 1 | -- FIXME: Although F1 usually outputs ^[OP, this test will fail 2 | -- when the terminal outputs something else instead. 3 | 4 | -- edit-insert-quoted F1 Return 5 | -- file-save file-quit 6 | call_command ("macro-play", "Ctrl-Alt-q", "F1", "Return", "Ctrl-s", "Ctrl-q") 7 | -------------------------------------------------------------------------------- /tests/regression/33910_execute-kbd-macro_with_edit-insert-quoted.output: -------------------------------------------------------------------------------- 1 | OP 2 | Here is a sample file. 3 | It has several lines. 4 | 5 | And more than one paragraph. 6 | -------------------------------------------------------------------------------- /tests/regression/34086_call-last-kbd-macro.lua: -------------------------------------------------------------------------------- 1 | -- macro-record "foo" Return Up macro-stop 2 | -- call-last-kbd-macro call-last-kbd-macro call-last-kbd-macro file-save file-quit 3 | call_command ("macro-play", "Ctrl-Alt-x", "m", "a", "c", "r", "o", "-", "r", "e", "c", "o", "r", "d", "Return", "f", "o", "o", "Return", "Up", "Ctrl-Alt-x", "m", "a", "c", "r", "o", "-", "s", "t", "o", "p", "Return", "Alt-Return", "Alt-Return", "Alt-Return", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/regression/34086_call-last-kbd-macro.output: -------------------------------------------------------------------------------- 1 | foo 2 | foo 3 | foo 4 | foo 5 | Here is a sample file. 6 | It has several lines. 7 | 8 | And more than one paragraph. 9 | -------------------------------------------------------------------------------- /tests/regression/34087_undo_macro.lua: -------------------------------------------------------------------------------- 1 | -- macro-record foo Return macro-stop call-last-kbd-macro undo 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-Alt-x", "m", "a", "c", "r", "o", "-", "r", "e", "c", "o", "r", "d", "Return", "f", "o", "o", "Return", "Ctrl-Alt-x", "m", "a", "c", "r", "o", "-", "s", "t", "o", "p", "Return", "Alt-m", "Ctrl-_", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/regression/34087_undo_macro.output: -------------------------------------------------------------------------------- 1 | foo 2 | Here is a sample file. 3 | It has several lines. 4 | 5 | And more than one paragraph. 6 | -------------------------------------------------------------------------------- /tests/regression/34193_interactive_insert.lua: -------------------------------------------------------------------------------- 1 | -- Regression: 2 | -- crash after accepting an empty argument to insert 3 | 4 | -- insert Return 5 | -- file-save file-quit 6 | call_command ("macro-play", "Ctrl-Alt-x", "i", "n", "s", "e", "r", "t", "Return", "Ctrl-g", "Ctrl-s", "Ctrl-q") 7 | -------------------------------------------------------------------------------- /tests/regression/34193_interactive_insert.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/regression/35562_search-backward.lua: -------------------------------------------------------------------------------- 1 | -- Alt-x search-backward Return Ctrl-g 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-Alt-x", "s", "e", "a", "r", "c", "h", "-", "b", "a", "c", "k", "w", "a", "r", "d", "Return", "Ctrl-g", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/regression/35562_search-backward.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /tests/regression/35567_minibuffer_ding_non_printable.lua: -------------------------------------------------------------------------------- 1 | -- edit-shell-command "echo foo" Alt-x Return file-save file-quit 2 | call_command ("macro-play", "Ctrl-Alt-s", "e", "c", "h", "o", "Space", "f", "o", "o", "Alt-x", "Return", "Ctrl-s", "Ctrl-q") 3 | -------------------------------------------------------------------------------- /tests/regression/35567_minibuffer_ding_non_printable.output: -------------------------------------------------------------------------------- 1 | foo 2 | Here is a sample file. 3 | It has several lines. 4 | 5 | And more than one paragraph. 6 | -------------------------------------------------------------------------------- /tests/regression/forward-char_at_end.lua: -------------------------------------------------------------------------------- 1 | -- move-end-file a move-next-character 2 | -- file-save file-quit 3 | call_command ("macro-play", "Ctrl-End", "a", "Right", "Ctrl-s", "Ctrl-q") 4 | -------------------------------------------------------------------------------- /tests/regression/forward-char_at_end.output: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | a -------------------------------------------------------------------------------- /tests/test.input: -------------------------------------------------------------------------------- 1 | Here is a sample file. 2 | It has several lines. 3 | 4 | And more than one paragraph. 5 | -------------------------------------------------------------------------------- /zee-git-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | build_command = "LUA=$(LUA) autoreconf -i && ./configure --prefix=$(PREFIX) --libdir=$(LIBDIR) --datadir=$(LUADIR) && make clean && make", 3 | copy_directories = { 4 | }, 5 | install_command = "make install", 6 | type = "command", 7 | } 8 | dependencies = { 9 | "lua == 5.3", 10 | "stdlib >= 41.2.0", 11 | "luaposix == 33.3.1", 12 | "lrexlib-gnu >= 2.8.0", 13 | "alien >= 0.7.1", 14 | } 15 | description = { 16 | detailed = "Zee is a lightweight editor. Zee is aimed at small footprint\ 17 | systems and quick editing sessions (it starts up and shuts down\ 18 | instantly).", 19 | homepage = "http://github.com/rrthomas/zee/", 20 | license = "GPLv3+", 21 | summary = "Experimental lightweight editor", 22 | } 23 | package = "zee" 24 | source = { 25 | url = "git://github.com/rrthomas/zee.git", 26 | } 27 | version = "git-1" 28 | -------------------------------------------------------------------------------- /zee/.gitignore: -------------------------------------------------------------------------------- 1 | /TAGS 2 | /zee 3 | /init.lua 4 | -------------------------------------------------------------------------------- /zee/astr.lua: -------------------------------------------------------------------------------- 1 | -- Efficient string buffers 2 | -- 3 | -- Copyright (c) 2011-2015 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | local Object = require "std.object" 21 | 22 | alien.default.memchr:types ("pointer", "pointer", "int", "size_t") 23 | 24 | local allocation_chunk_size = 16 25 | AStr = Object { 26 | -- Primitive methods 27 | 28 | _init = function (self, init, len) 29 | if type (init) == "string" then 30 | self.buf = alien.array ("char", #init, alien.buffer (init)) 31 | self.length = #init 32 | elseif type (init) == "number" then 33 | self.buf = alien.array ("char", math.max (init, 1)) 34 | self.length = init 35 | elseif type (init) == "userdata" then 36 | self.buf = alien.array ("char", len, alien.buffer (init)) 37 | self.length = len 38 | else 39 | self.buf = alien.array ("char", init) 40 | self.length = #init 41 | end 42 | return self 43 | end, 44 | 45 | __tostring = function (self) 46 | return self.buf.buffer:tostring (#self) 47 | end, 48 | 49 | __index = function (self, n) 50 | return self.buf[n] 51 | end, 52 | 53 | __len = function (self) 54 | return self.length 55 | end, 56 | 57 | sub = function (self, from, to) 58 | to = to or self.length 59 | return AStr (self:topointer (from), to - from + 1) 60 | end, 61 | 62 | set_len = function (self, n) 63 | if n > self.buf.length or n < self.buf.length / 2 then 64 | self.buf:realloc (n + allocation_chunk_size) 65 | end 66 | self.length = n 67 | end, 68 | 69 | move = function (self, to, from, n) 70 | assert (math.max (from, to) + n <= #self + 1) 71 | alien.memmove (self:topointer (to), self:topointer (from), n) 72 | end, 73 | 74 | set = function (self, from, c, n) 75 | assert (from + n <= #self + 1) 76 | alien.memset (self:topointer (from), c:byte (), n) 77 | end, 78 | 79 | remove = function (self, from, n) 80 | local b, e, eob = from, from + n, #self + 1 81 | assert (e <= eob) 82 | self:move (e, b, eob - e) 83 | self:set_len (#self - n) 84 | end, 85 | 86 | insert = function (self, from, n) 87 | assert (from <= #self + 1) 88 | self:set_len (#self + n) 89 | self:move (from + n, from, #self + 1 - (from + n)) 90 | self:set (from, '\0', n) 91 | end, 92 | 93 | replace = function (self, from, rep, len) 94 | local len = len or #rep 95 | assert (from + len <= #self + 1) 96 | if type (rep) ~= "userdata" and type (rep) ~= "string" then 97 | rep = rep:topointer () 98 | end 99 | alien.memmove (self:topointer (from), rep, len) 100 | return self 101 | end, 102 | 103 | rchr = function (self, c, from) 104 | local b = self.buf 105 | for i = from - 1, 1, -1 do 106 | if b[i] == c then return i end 107 | end 108 | end, 109 | 110 | start_of_line = function (self, o) 111 | local prev = self:rchr (string.byte ('\n'), o) 112 | return prev and prev + 1 or 1 113 | end, 114 | 115 | end_of_line = function (self, o) 116 | local next = alien.default.memchr (self:topointer (o), string.byte ('\n'), #self - (o - 1)) 117 | return next and self.buf.buffer:tooffset (next) or #self + 1 118 | end, 119 | 120 | 121 | -- Derived methods 122 | 123 | topointer = function (self, offset) 124 | return self.buf.buffer:topointer (offset) 125 | end, 126 | 127 | cat = function (self, src) 128 | local oldlen = #self 129 | self:insert (oldlen + 1, #src) 130 | return self:replace (oldlen + 1, src:topointer (), #src) 131 | end, 132 | 133 | prev_line = function (self, o) 134 | local so = self:start_of_line (o) 135 | return so ~= 1 and self:start_of_line (so - 1) or nil 136 | end, 137 | 138 | next_line = function (self, o) 139 | local eo = self:end_of_line (o) 140 | return eo <= #self and eo + 1 or nil 141 | end, 142 | 143 | lines = function (self) 144 | local lines = -1 145 | local next = 1 146 | repeat 147 | next = self:next_line (next) 148 | lines = lines + 1 149 | until not next 150 | return lines 151 | end, 152 | } 153 | 154 | local have_memrchr = pcall (load 'alien.default.memrchr:types ("pointer", "pointer", "int", "size_t")') 155 | if have_memrchr then 156 | AStr.rchr = function (self, c, from) 157 | local p = alien.default.memrchr(self:topointer (), c, from - 1) 158 | return p and self.buf.buffer:tooffset (p) 159 | end 160 | end 161 | -------------------------------------------------------------------------------- /zee/bind.lua: -------------------------------------------------------------------------------- 1 | -- Key bindings 2 | -- 3 | -- Copyright (c) 2010-2015 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | -- Key binding. 21 | 22 | _last_command = nil 23 | _this_command = nil 24 | _interactive = 0 25 | 26 | function interactive () 27 | return _interactive > 0 28 | end 29 | 30 | function call_command (f, ...) 31 | thisflag = {defining_macro = lastflag.defining_macro} 32 | 33 | -- Execute the command. 34 | _this_command = f 35 | _interactive = _interactive + 1 36 | local ok = not execute_command (f, ...) -- FIXME: Most of this (except _interactive) should be inside execute_command 37 | _interactive = math.max (0, _interactive - 1) 38 | _last_command = _this_command 39 | 40 | if buf and _last_command ~= "edit-undo" then 41 | buf.next_undo = buf.last_undo 42 | end 43 | 44 | lastflag = thisflag 45 | 46 | return ok 47 | end 48 | 49 | function get_and_run_command () 50 | local key = get_key_chord () 51 | local name = binding_to_command (key) 52 | 53 | popup_clear () 54 | minibuf_clear () 55 | 56 | if command_exists (name) then 57 | call_command (name) 58 | else 59 | minibuf_error (tostring (key) .. " is undefined") 60 | end 61 | end 62 | 63 | root_bindings = {} 64 | bindings = root_bindings 65 | 66 | local function key_canon (keystr) 67 | local key = tostring (keycode (keystr)) -- canonicalize the string 68 | if not key then 69 | minibuf_error (string.format ("Key sequence %s is invalid", keystr)) 70 | return 71 | end 72 | return key 73 | end 74 | 75 | function key_unbind (keystr) 76 | local key = key_canon (keystr) 77 | if key then 78 | bindings[key] = nil 79 | end 80 | end 81 | 82 | function key_bind (keystr, cmd) 83 | local key = key_canon (keystr) 84 | if key then 85 | if not command_exists (cmd) then -- Possible if called non-interactively 86 | minibuf_error (string.format ("No such function `%s'", cmd)) 87 | return 88 | end 89 | 90 | bindings[key] = cmd 91 | end 92 | end 93 | 94 | function bind_printing_chars (cmd) 95 | -- Bind all printing keys to given command 96 | for i = 0, 0xff do 97 | if posix.isprint (string.char (i)) then 98 | bindings[string.char (i)] = cmd 99 | end 100 | end 101 | -- Bind special key names to edit-insert-character 102 | functional.map (function (e) 103 | bindings[tostring (keycode (e))] = cmd 104 | end, 105 | std.ielems, 106 | {"Space", "Tab", "Return"}) 107 | end 108 | 109 | bind_printing_chars ("edit-insert-character") 110 | -- FIXME: Make Escape bindable and make it possible to escape to top level 111 | 112 | function binding_to_command (key) 113 | return bindings[tostring (key)] 114 | end 115 | 116 | function command_to_binding (cmd) 117 | local keys = {} 118 | for k, n in pairs (bindings) do 119 | if n == cmd then 120 | table.insert (keys, k) 121 | end 122 | end 123 | return keys 124 | end 125 | -------------------------------------------------------------------------------- /zee/buffer.lua: -------------------------------------------------------------------------------- 1 | -- Buffer type, functions and commands 2 | -- 3 | -- Copyright (c) 2010-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | 21 | -- Buffer methods that know about the gap. 22 | 23 | function get_buffer_pre_cursor (bp) 24 | return bp.text:sub (1, get_buffer_pt (bp) - 1) 25 | end 26 | 27 | function get_buffer_post_cursor (bp) 28 | return bp.text:sub (get_buffer_pt (bp) + bp.gap) 29 | end 30 | 31 | function get_buffer_pt (bp) 32 | return bp.pt 33 | end 34 | 35 | local function set_buffer_pt (bp, o) 36 | if o < bp.pt then 37 | bp.text:move (o + bp.gap, o, bp.pt - o) 38 | bp.text:set (o, '\0', math.min (bp.pt - o, bp.gap)) 39 | elseif o > bp.pt then 40 | bp.text:move (bp.pt, bp.pt + bp.gap, o - bp.pt) 41 | bp.text:set (o + bp.gap - math.min (o - bp.pt, bp.gap), '\0', math.min (o - bp.pt, bp.gap)) 42 | end 43 | bp.pt = o 44 | end 45 | 46 | local function realo_to_o (bp, o) 47 | if o == nil then 48 | return o 49 | elseif o <= bp.pt then 50 | return o 51 | elseif o >= bp.pt + bp.gap then 52 | return o - bp.gap 53 | end 54 | assert (false) -- FIXME: crash with an error 55 | end 56 | 57 | local function o_to_realo (bp, o) 58 | return o < bp.pt and o or o + bp.gap 59 | end 60 | 61 | function get_buffer_size (bp) 62 | return realo_to_o (bp, #bp.text + 1) - 1 63 | end 64 | 65 | function buffer_line_len (bp, o) 66 | o = o or get_buffer_line_o (bp) 67 | return realo_to_o (bp, bp.text:end_of_line (o_to_realo (bp, o))) - 68 | realo_to_o (bp, bp.text:start_of_line (o_to_realo (bp, o))) 69 | end 70 | 71 | -- Replace `del' chars after cursor with `s'. 72 | -- `s' can be a string or an AStr. 73 | local min_gap = 1024 -- Minimum gap size after resize 74 | local max_gap = 4096 -- Maximum permitted gap size 75 | function replace_string (del, s) 76 | if buf.readonly then 77 | minibuf_error ("File is readonly") 78 | return false 79 | end 80 | 81 | local newlen = #s 82 | undo_save_block (buf.pt, del, newlen) 83 | 84 | -- Adjust gap. 85 | local oldgap = buf.gap 86 | if oldgap + del < newlen then 87 | -- If gap would vanish, open it to min_gap. 88 | buf.text:insert (buf.pt, (newlen + min_gap) - (buf.gap + del)) 89 | buf.gap = min_gap 90 | else 91 | if oldgap + del > max_gap + newlen then 92 | -- If gap would be larger than max_gap, restrict it to max_gap. 93 | buf.text:remove (buf.pt + newlen + max_gap, (oldgap + del) - (max_gap + newlen)) 94 | buf.gap = max_gap 95 | else 96 | buf.gap = oldgap + del - newlen 97 | end 98 | 99 | -- Zero any new bit of gap. 100 | if buf.gap > oldgap then 101 | buf.text:set (buf.pt + oldgap, '\0', buf.gap - oldgap) 102 | end 103 | end 104 | 105 | -- Insert `newlen' chars. 106 | buf.text:replace (buf.pt + buf.gap, s) 107 | 108 | -- Adjust markers. 109 | for m in pairs (buf.markers) do 110 | if m.o > buf.pt then 111 | m.o = math.max (buf.pt, m.o + newlen - del) 112 | end 113 | end 114 | 115 | buf.modified = true 116 | return true 117 | end 118 | 119 | function insert_string (s) 120 | local ok = replace_string (0, s) 121 | if ok then 122 | assert (move_char (#s)) 123 | end 124 | return ok 125 | end 126 | 127 | function get_buffer_char (bp, o) 128 | local n = o_to_realo (bp, o) 129 | return string.char (bp.text[n]) 130 | end 131 | 132 | function buffer_prev_line (bp, o) 133 | return realo_to_o (bp, bp.text:prev_line (o_to_realo (bp, o))) 134 | end 135 | 136 | function buffer_next_line (bp, o) 137 | return realo_to_o (bp, bp.text:next_line (o_to_realo (bp, o))) 138 | end 139 | 140 | function buffer_start_of_line (bp, o) 141 | return realo_to_o (bp, bp.text:start_of_line (o_to_realo (bp, o))) 142 | end 143 | 144 | function buffer_end_of_line (bp, o) 145 | return realo_to_o (bp, bp.text:end_of_line (o_to_realo (bp, o))) 146 | end 147 | 148 | function get_buffer_line_o (bp) 149 | return realo_to_o (bp, bp.text:start_of_line (o_to_realo (bp, bp.pt))) 150 | end 151 | 152 | -- Copy a region of text into an AStr. 153 | function get_buffer_region (bp, r) 154 | local as = AStr (r.finish - r.start) 155 | if r.start < get_buffer_pt (bp) then 156 | as:replace (1, bp.text:sub (r.start, math.min (r.finish, get_buffer_pt (bp)) - 1)) 157 | end 158 | if r.finish > get_buffer_pt (bp) then 159 | local n = r.start - get_buffer_pt (bp) 160 | local done = math.max (-n, 0) 161 | local from = math.max (n, 0) 162 | as:replace (done + 1, bp.text:sub (get_buffer_pt (bp) + bp.gap + from, bp.gap + r.finish - 1)) 163 | end 164 | return as 165 | end 166 | 167 | 168 | -- Buffer methods that don't know about the gap. 169 | 170 | function get_buffer_line (bp) 171 | return bp.line 172 | end 173 | 174 | -- Get filename. 175 | function get_buffer_filename (bp) 176 | return bp.filename 177 | end 178 | 179 | 180 | function delete_char () 181 | execute_command ("edit-select-off") 182 | 183 | if end_of_buffer () then 184 | return minibuf_error ("End of buffer") 185 | end 186 | 187 | if end_of_line () then 188 | thisflag.need_resync = true 189 | end 190 | buf.modified = replace_string (1, "") 191 | return buf.modified 192 | end 193 | 194 | 195 | -- Allocate a new buffer, set the default local variable values, and 196 | -- insert it into the buffer list. 197 | function buffer_new () -- FIXME: Constructor which we can pass other arguments 198 | return {pt = 1, line = 0, gap = 0, text = AStr (""), 199 | markers = setmetatable ({}, {__mode = "k"}), 200 | modified = false} 201 | end 202 | 203 | -- Make a region from two offsets 204 | function region_new (o1, o2) 205 | return {start = math.min (o1, o2), finish = math.max (o1, o2)} 206 | end 207 | 208 | function get_region_size (rp) 209 | return rp.finish - rp.start 210 | end 211 | 212 | -- Return the selection 213 | function calculate_the_selection () 214 | if not buf.mark then 215 | return minibuf_error ("There is no selection") 216 | end 217 | 218 | return region_new (buf.pt, buf.mark.o) 219 | end 220 | 221 | function delete_region (r) 222 | goto_offset (r.start) 223 | replace_string (get_region_size (r), "") 224 | end 225 | 226 | function in_region (o, x, r) 227 | return o + x >= r.start and o + x < r.finish 228 | end 229 | 230 | 231 | -- Marker datatype 232 | 233 | local function marker_new (o) 234 | local marker = {o = o} 235 | buf.markers[marker] = true 236 | return marker 237 | end 238 | 239 | function copy_marker (m) 240 | return marker_new (m.o) 241 | end 242 | 243 | function cursor_marker () 244 | return marker_new (get_buffer_pt (buf)) 245 | end 246 | 247 | Define ("edit-select-on", 248 | [[ 249 | Start selecting text. 250 | ]], 251 | function () 252 | buf.mark = cursor_marker () 253 | end 254 | ) 255 | 256 | Define ("edit-select-off", 257 | [[ 258 | Stop selecting text. 259 | ]], 260 | function () 261 | buf.mark = nil 262 | end 263 | ) 264 | 265 | Define ("edit-select-toggle", 266 | [[ 267 | Toggle selection mode. 268 | ]], 269 | function () 270 | if buf.mark then 271 | execute_command ("edit-select-off") 272 | else 273 | execute_command ("edit-select-on") 274 | end 275 | end 276 | ) 277 | 278 | Define ("edit-select-other-end", 279 | [[ 280 | When selecting text, move the cursor to the other end of the selection. 281 | ]], 282 | function () 283 | if not buf.mark then 284 | return minibuf_error ("No selection") 285 | end 286 | 287 | local tmp = get_buffer_pt (buf) 288 | goto_offset (buf.mark.o) 289 | buf.mark.o = tmp 290 | thisflag.need_resync = true 291 | end 292 | ) 293 | 294 | tab_width = 8 295 | 296 | -- Return a safe indent width. 297 | function indent_width () 298 | return math.max (tonumber (get_variable ("indent-width")), 1) 299 | end 300 | 301 | 302 | -- Basic movement routines 303 | 304 | function move_char (n) 305 | local ltest, new_goalc, n2 306 | if n > 0 then 307 | ltest, new_goalc = end_of_line, 0 308 | n2 = math.min (n, get_buffer_size (buf) + 1 - get_buffer_pt (buf)) 309 | else 310 | ltest, new_goalc = beginning_of_line, math.huge 311 | n2 = math.max (n, -get_buffer_pt (buf) + 1) 312 | end 313 | 314 | -- Count lines we're about to move over. 315 | local r 316 | if n2 < 0 then 317 | r = buf.text:sub (get_buffer_pt (buf) + n2, get_buffer_pt (buf) - 1) 318 | else 319 | r = buf.text:sub (get_buffer_pt (buf) + buf.gap, get_buffer_pt (buf) + buf.gap + n2 - 1) 320 | end 321 | local _, lines = rex_gnu.gsub (r, "\n", "%0") 322 | if lines > 0 then 323 | thisflag.need_resync = true 324 | buf.line = buf.line + lines * (n2 > 0 and 1 or -1) 325 | end 326 | 327 | -- Move. 328 | set_buffer_pt (buf, get_buffer_pt (buf) + n2) 329 | 330 | -- If we moved to a line end from inside the line, set goalc to an extreme value. 331 | if ltest () then 332 | set_goalc (new_goalc) 333 | end 334 | 335 | return n == n2 336 | end 337 | 338 | function goto_offset (o) 339 | move_char (o - get_buffer_pt (buf)) 340 | end 341 | 342 | -- Get the goal column, expanding tabs. 343 | function get_goalc () 344 | return #make_string_printable (get_line ():sub (1, get_buffer_pt (buf) - get_buffer_line_o (buf))) 345 | end 346 | 347 | function set_goalc (c) 348 | buf.goalc = c 349 | end 350 | 351 | function move_line (n) 352 | local dir, func = 1, buffer_next_line 353 | if n < 0 then 354 | dir, func = -1, buffer_prev_line 355 | n = -n 356 | end 357 | 358 | if _last_command ~= "move-next-line" and _last_command ~= "move-previous-line" then 359 | set_goalc (get_goalc ()) 360 | end 361 | 362 | while n > 0 do 363 | local o = func (buf, buf.pt) 364 | if o == nil then 365 | break 366 | end 367 | set_buffer_pt (buf, o) 368 | n = n - 1 369 | buf.line = buf.line + dir 370 | end 371 | 372 | set_buffer_pt (buf, get_buffer_line_o (buf) + #make_string_printable (get_line (), buf.goalc)) 373 | thisflag.need_resync = true 374 | return n ~= 0 375 | end 376 | 377 | function get_line () 378 | return get_buffer_region (buf, region_new (get_buffer_line_o (buf), buffer_end_of_line (buf, get_buffer_pt (buf)))) 379 | end 380 | 381 | function is_empty_line () 382 | return buffer_line_len (buf) == 0 383 | end 384 | 385 | function is_blank_line () 386 | return regex_match (get_line (), "^[ \t]*$") 387 | end 388 | 389 | -- Returns the character following the cursor. 390 | function following_char () 391 | if end_of_buffer () then 392 | return nil 393 | end 394 | return get_buffer_char (buf, get_buffer_pt (buf)) 395 | end 396 | 397 | -- Return the character preceding the cursor. 398 | function preceding_char () 399 | if beginning_of_buffer () then 400 | return nil 401 | end 402 | return get_buffer_char (buf, get_buffer_pt (buf) - 1) 403 | end 404 | 405 | -- Return true if cursor is at the beginning of the buffer. 406 | function beginning_of_buffer () 407 | return get_buffer_pt (buf) == 1 408 | end 409 | 410 | -- Return true if cursor is at the end of the buffer. 411 | function end_of_buffer (void) 412 | return get_buffer_pt (buf) > get_buffer_size (buf) 413 | end 414 | 415 | -- Return true if cursor is at the beginning of a line. 416 | function beginning_of_line () 417 | return get_buffer_pt (buf) == get_buffer_line_o (buf) 418 | end 419 | 420 | -- Return true if cursor is at the end of a line. 421 | function end_of_line () 422 | return get_buffer_pt (buf) - get_buffer_line_o (buf) == buffer_line_len (buf) 423 | end 424 | -------------------------------------------------------------------------------- /zee/completion.lua: -------------------------------------------------------------------------------- 1 | -- Completion facility functions 2 | -- 3 | -- Copyright (c) 2007, 2009-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | -- Completions table: 21 | -- { 22 | -- completions: list of completion strings 23 | -- matches: list of matches 24 | -- match: the current matched string 25 | -- } 26 | -- FIXME: Use Objects here and elsewhere, and add an __index 27 | -- metamethod that works like strict.lua. 28 | 29 | -- Make a new completions table 30 | function completion_new (completions) 31 | return {completions = set (completions or {}), matches = {}} 32 | end 33 | 34 | -- Write the matches in `l' in a set of columns. The width of the 35 | -- columns is chosen to be big enough for the longest string, with a 36 | -- COLUMN_GAP-character gap between each column. 37 | local COLUMN_GAP = 3 38 | function completion_write (cp, width) 39 | local maxlen = 0 40 | for i, v in ipairs (cp.matches) do 41 | maxlen = math.max (maxlen, #v) 42 | end 43 | maxlen = maxlen + COLUMN_GAP 44 | local numcols = math.floor ((width - 1) / maxlen) 45 | local col = 0 46 | 47 | local s = "Possible completions are:\n" 48 | for i, v in ipairs (cp.matches) do 49 | s = s .. string.format ("%-" .. maxlen .. "s", v) 50 | col = (col + 1) % numcols 51 | if col == 0 then 52 | s = s .. '\n' 53 | end 54 | end 55 | return s 56 | end 57 | 58 | -- Returns the length of the common prefix of s1 and s2. 59 | local function common_prefix_length (s1, s2) 60 | local len = math.min (#s1, #s2) 61 | for i = 1, len do 62 | if s1:sub (i, i) ~= s2:sub (i, i) then 63 | return i - 1 64 | end 65 | end 66 | return len 67 | end 68 | 69 | -- Arguments: 70 | -- 71 | -- cp - the completions 72 | -- search - the prefix to search for 73 | -- 74 | -- Returns false if `search' is not a prefix of any completion, and true 75 | -- otherwise. 76 | -- 77 | -- The effect on cp is as follows: 78 | -- 79 | -- completions - unchanged 80 | -- matches - replaced with the list of matching completions, sorted 81 | -- match - replaced with the longest common prefix of the matches 82 | -- 83 | -- To format the completions for a popup, call completion_write 84 | -- after this function. 85 | -- FIXME: To see the completions in a popup, you should call 86 | -- completion_popup after this method. You may want to call 87 | -- completion_remove_suffix and/or completion_remove_prefix in between 88 | -- to keep the list manageable. (See C Zee's completion.lua.) 89 | function completion_try (cp, search) 90 | cp.matches = {} 91 | 92 | local fullmatch = false 93 | for c in pairs (cp.completions) do 94 | if type (c) == "string" then 95 | if string.sub (c, 1, #search) == search then 96 | table.insert (cp.matches, c) 97 | if c == search then 98 | fullmatch = true 99 | end 100 | end 101 | end 102 | end 103 | 104 | if #cp.matches == 0 then 105 | return false 106 | end 107 | 108 | table.sort (cp.matches) 109 | cp.match = cp.matches[1] 110 | local prefix_len = #cp.match 111 | for _, v in ipairs (cp.matches) do 112 | prefix_len = math.min (prefix_len, common_prefix_length (cp.match, v)) 113 | end 114 | cp.match = cp.match:sub (1, prefix_len) 115 | 116 | return true 117 | end 118 | 119 | -- Popup the completion window. 120 | function popup_completion (cp) 121 | popup_set (completion_write (cp, win.ewidth)) 122 | term_display () 123 | end 124 | -------------------------------------------------------------------------------- /zee/cua_bindings.lua: -------------------------------------------------------------------------------- 1 | -- CUA key bindings 2 | 3 | -- Command execution 4 | key_bind ("Ctrl-Alt-x", "execute-command") 5 | key_bind ("Ctrl-Alt-s", "edit-shell-command") 6 | key_bind ("Ctrl-Alt-z", "file-suspend") 7 | 8 | -- Navigation. Mostly arrows and things. 9 | 10 | -- Character/line 11 | key_bind ("Left", "move-previous-character") 12 | key_bind ("Right", "move-next-character") 13 | key_bind ("Up", "move-previous-line") 14 | key_bind ("Down", "move-next-line") 15 | -- Word/paragraph 16 | key_bind ("Ctrl-Left", "move-previous-word") 17 | key_bind ("Ctrl-Right", "move-next-word") 18 | key_bind ("Alt-[", "move-previous-paragraph") -- FIXME 19 | key_bind ("Alt-]", "move-next-paragraph") -- FIXME 20 | -- Line/page 21 | key_bind ("Home", "move-start-line") 22 | key_bind ("End", "move-end-line") 23 | key_bind ("PageUp", "move-previous-page") 24 | key_bind ("PageDown", "move-next-page") 25 | -- Whole buffer 26 | key_bind ("Ctrl-Home", "move-start-file") 27 | key_bind ("Ctrl-End", "move-end-file") 28 | -- Window 29 | key_bind ("Ctrl-l", "view-refresh") 30 | 31 | -- Selection 32 | key_bind ("Ctrl-@", "edit-select-toggle") 33 | key_bind ("Alt-Space", "edit-select-other-end") -- FIXME 34 | 35 | -- Absolute navigation. These are like navigation commands but they 36 | -- don't become selection commands when combined with SHIFT. 37 | key_bind ("Ctrl-Alt-g", "move-goto-line") 38 | key_bind ("Ctrl-Alt-c", "move-goto-column") 39 | 40 | -- Save 41 | key_bind ("Ctrl-s", "file-save") 42 | -- Quit 43 | key_bind ("Ctrl-q", "file-quit") 44 | 45 | -- Undo 46 | key_bind ("Ctrl-z", "edit-undo") 47 | -- Cut selection to clipboard 48 | key_bind ("Ctrl-x", "edit-cut") 49 | key_bind ("Ctrl-Delete", "edit-delete-word") 50 | -- Copy selection to clipboard 51 | key_bind ("Ctrl-c", "edit-copy") 52 | -- Delete without modifying clipboard 53 | key_bind ("Backspace", "edit-delete-previous-character") 54 | key_bind ("Ctrl-?", "edit-delete-previous-character") 55 | key_bind ("Ctrl-Backspace", "edit-delete-word-backward") 56 | key_bind ("Ctrl-Alt-?", "edit-delete-word-backward") 57 | key_bind ("Delete", "edit-delete-next-character") 58 | key_bind ("Ctrl-Alt-d", "edit-delete-horizontal-space") 59 | -- Paste 60 | key_bind ("Ctrl-v", "edit-paste") 61 | 62 | -- Search 63 | key_bind ("Ctrl-f", "edit-find") 64 | key_bind ("Ctrl-Alt-f", "edit-find-backward") 65 | key_bind ("Ctrl-r", "edit-replace") 66 | 67 | -- Insert special characters 68 | key_bind ("Alt-Tab", "edit-indent") -- FIXME: Should be Ctrl-Alt-i 69 | key_bind ("Ctrl-Alt-q", "edit-insert-quoted") 70 | key_bind ("Tab", "edit-indent-relative") 71 | key_bind ("Ctrl-Return", "edit-insert-newline") -- FIXME: binding doesn't work 72 | key_bind ("Return", "edit-insert-newline-and-indent") 73 | 74 | -- Macros 75 | key_bind ("Ctrl-(", "macro-record") 76 | key_bind ("Ctrl-)", "macro-stop") 77 | key_bind ("Alt-Return", "macro-play") -- FIXME 78 | -------------------------------------------------------------------------------- /zee/cut.lua: -------------------------------------------------------------------------------- 1 | -- Cut and paste 2 | -- 3 | -- Copyright (c) 2010-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | local cut_buffer_text = AStr ("") 21 | 22 | local function copy_or_cut_the_region (cut) 23 | local r = calculate_the_selection () 24 | if r == true then 25 | return true 26 | end 27 | 28 | cut_buffer_text = get_buffer_region (buf, r) 29 | if cut then 30 | if buf.readonly then 31 | minibuf_error ("Read only text copied to cut buffer") 32 | else 33 | delete_region (r) 34 | end 35 | end 36 | execute_command ("edit-select-off") 37 | end 38 | 39 | Define ("edit-cut", 40 | [[ 41 | Cut the selection. 42 | The text is deleted, unless the buffer is read-only, and saved in the 43 | paste buffer; the `edit-paste' command retrieves it. 44 | ]], 45 | function () 46 | return copy_or_cut_the_region (true) 47 | end 48 | ) 49 | 50 | Define ("edit-copy", 51 | [[ 52 | Copy the selection to the paste buffer. 53 | ]], 54 | function () 55 | return copy_or_cut_the_region (false) 56 | end 57 | ) 58 | 59 | Define ("edit-paste", 60 | [[ 61 | Insert the contents of the paste buffer. 62 | ]], 63 | function () 64 | return not insert_string (cut_buffer_text) 65 | end 66 | ) 67 | -------------------------------------------------------------------------------- /zee/edit.lua: -------------------------------------------------------------------------------- 1 | -- Basic editing functions 2 | -- 3 | -- Copyright (c) 2010-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program; see the file COPYING. If not, write to the 19 | -- Free Software Foundation, Fifth Floor, 51 Franklin Street, Boston, 20 | -- MA 02111-1301, USA. 21 | 22 | Define ("edit-insert-character", 23 | [[ 24 | Insert the character you type. 25 | Whichever character you type to run this command is inserted. 26 | ]], 27 | function (key) 28 | local key = key and key:byte () or term_keytobyte (lastkey ()) 29 | execute_command ("edit-select-off") 30 | if not key then 31 | return ding () 32 | end 33 | insert_string (string.char (key)) 34 | end 35 | ) 36 | 37 | -- Indentation command 38 | -- Go to cur_goalc () in the previous non-blank line. 39 | local function previous_nonblank_goalc () 40 | local cur_goalc = get_goalc () 41 | local ok = true 42 | 43 | -- Find previous non-blank line, if any. 44 | repeat 45 | ok = not move_line (-1) 46 | until not ok or not is_blank_line () 47 | 48 | -- Go to `cur_goalc' in that non-blank line. 49 | while ok and not end_of_line () and get_goalc () < cur_goalc do 50 | ok = move_char (1) 51 | end 52 | end 53 | 54 | Define ("edit-indent-relative", 55 | [[ 56 | Indent line or insert a tab. 57 | ]], 58 | function () 59 | local cur_goalc = get_goalc () 60 | local target_goalc = 0 61 | local m = cursor_marker () 62 | local ok 63 | 64 | execute_command ("edit-select-off") 65 | previous_nonblank_goalc () 66 | 67 | -- Now find the next blank char. 68 | if preceding_char () ~= '\t' or get_goalc () <= cur_goalc then 69 | while not end_of_line () and not following_char ():match ("%s") do 70 | move_char (1) 71 | end 72 | end 73 | 74 | -- Find next non-blank char. 75 | while not end_of_line () and following_char ():match ("%s") do 76 | move_char (1) 77 | end 78 | 79 | -- Target column. 80 | if not end_of_line () then 81 | target_goalc = get_goalc () 82 | end 83 | goto_offset (m.o) 84 | 85 | -- Indent. 86 | undo_start_sequence () 87 | if target_goalc > 0 then 88 | -- If not at EOL on target line, insert spaces & tabs up to 89 | -- target_goalc. 90 | while get_goalc () < target_goalc do 91 | ok = insert_string (' ') 92 | end 93 | else 94 | -- if already at EOL on target line, insert a tab. 95 | ok = call_command ("insert-tab") 96 | end 97 | undo_end_sequence () 98 | 99 | return ok 100 | end 101 | ) 102 | 103 | Define ("edit-insert-newline-and-indent", 104 | [[ 105 | Insert a newline, then indent. 106 | Indentation is done using the `edit-indent-relative' function, except 107 | that if there is a character in the first column of the line above, 108 | no indenting is performed. 109 | ]], 110 | function () 111 | execute_command ("edit-select-off") 112 | 113 | undo_start_sequence () 114 | if insert_string ("\n") then 115 | local m = cursor_marker () 116 | local pos 117 | 118 | -- Check where last non-blank goalc is. 119 | previous_nonblank_goalc () 120 | pos = get_goalc () 121 | local indent = pos > 0 or (not end_of_line () and following_char ():match ("%s")) 122 | goto_offset (m.o) 123 | -- Only indent if we're in column > 0 or we're in column 0 and 124 | -- there is a space character there in the last non-blank line. 125 | if indent then 126 | execute_command ("edit-indent-relative") 127 | end 128 | end 129 | undo_end_sequence () 130 | end 131 | ) 132 | 133 | 134 | Define ("edit-delete-next-character", 135 | [[ 136 | Delete the following character. 137 | Join lines if the character is a newline. 138 | ]], 139 | function () 140 | delete_char () 141 | end 142 | ) 143 | 144 | Define ("edit-delete-previous-character", 145 | [[ 146 | Delete the previous character. 147 | Join lines if the character is a newline. 148 | ]], 149 | function () 150 | if not move_char (-1) then 151 | minibuf_error ("Beginning of buffer") 152 | return true 153 | end 154 | 155 | delete_char () 156 | end 157 | ) 158 | 159 | Define ("edit-delete-horizontal-space", 160 | [[ 161 | Delete all spaces and tabs around the cursor. 162 | ]], 163 | function () 164 | undo_start_sequence () 165 | 166 | while not end_of_line () and following_char ():match ("%s") do 167 | delete_char () 168 | end 169 | 170 | while not beginning_of_line () and preceding_char ():match ("%s") do 171 | execute_command ("edit-delete-previous-character") 172 | end 173 | 174 | undo_end_sequence () 175 | end 176 | ) 177 | 178 | Define ("edit-indent", 179 | [[ 180 | Indent to next multiple of `indent-width'. 181 | ]], 182 | function () 183 | local t = indent_width () 184 | return not insert_string (string.rep (' ', t - get_goalc () % t)) 185 | end 186 | ) 187 | 188 | Define ("edit-insert-newline", 189 | [[ 190 | Insert a newline. 191 | ]], 192 | function () 193 | return not insert_string ("\n") 194 | end 195 | ) 196 | 197 | -- FIXME: Inserting a tab seems to insert some spaces too, and mess up 198 | -- the buffer (overwriting characters after the tab?) 199 | Define ("edit-insert-quoted", 200 | [[ 201 | Read next input character and insert it. 202 | This is useful for inserting control characters. 203 | ]], 204 | function () 205 | minibuf_write ("Ctrl-q-") 206 | insert_string (string.char (bit32.band (getkey_unfiltered (GETKEY_DEFAULT), 0xff))) 207 | minibuf_clear () 208 | end 209 | ) 210 | 211 | local function delete_text (move_func) 212 | local pt = get_buffer_pt (buf) 213 | undo_start_sequence () 214 | execute_command (move_func) 215 | delete_region (region_new (pt, get_buffer_pt (buf))) 216 | undo_end_sequence () 217 | goto_offset (pt) 218 | end 219 | 220 | Define ("edit-delete-word", 221 | [[ 222 | Delete forward up to the end of a word. 223 | ]], 224 | function () 225 | return delete_text ("move-next-word") 226 | end 227 | ) 228 | 229 | Define ("edit-delete-word-backward", 230 | [[ 231 | Delete backward up to the end of a word. 232 | ]], 233 | function () 234 | return delete_text ("move-previous-word") 235 | end 236 | ) 237 | -------------------------------------------------------------------------------- /zee/emacs_bindings.lua: -------------------------------------------------------------------------------- 1 | -- Emacs key bindings 2 | 3 | -- Command execution 4 | key_bind ("Alt-x", "execute-command") 5 | key_bind ("Alt-!", "edit-shell-command") 6 | 7 | -- Navigation. Mostly arrows and things. 8 | 9 | -- Character/line 10 | key_bind ("Left", "move-previous-character") 11 | key_bind ("Ctrl-b", "move-previous-character") 12 | key_bind ("Right", "move-next-character") 13 | key_bind ("Ctrl-f", "move-next-character") 14 | key_bind ("Up", "move-previous-line") 15 | key_bind ("Ctrl-p", "move-previous-line") 16 | key_bind ("Down", "move-next-line") 17 | key_bind ("Ctrl-n", "move-next-line") 18 | -- Word/paragraph 19 | key_bind ("Ctrl-Left", "move-previous-word") 20 | key_bind ("Alt-Left", "move-previous-word") 21 | key_bind ("Alt-b", "move-previous-word") 22 | key_bind ("Ctrl-Right", "move-next-word") 23 | key_bind ("Alt-Right", "move-next-word") 24 | key_bind ("Alt-f", "move-next-word") 25 | key_bind ("Alt-{", "move-previous-paragraph") 26 | key_bind ("Alt-}", "move-next-paragraph") 27 | -- Line/page 28 | key_bind ("Home", "move-start-line") 29 | key_bind ("Ctrl-a", "move-start-line") 30 | key_bind ("End", "move-end-line") 31 | key_bind ("Ctrl-e", "move-end-line") 32 | key_bind ("PageUp", "move-previous-page") 33 | key_bind ("Alt-v", "move-previous-page") 34 | key_bind ("PageDown", "move-next-page") 35 | key_bind ("Ctrl-v", "move-next-page") 36 | -- Whole buffer 37 | key_bind ("Ctrl-Home", "move-start-file") 38 | key_bind ("Alt-<", "move-start-file") 39 | key_bind ("Ctrl-End", "move-end-file") 40 | key_bind ("Alt->,", "move-end-file") 41 | -- Window 42 | key_bind ("Ctrl-l", "view-refresh") 43 | 44 | -- Absolute navigation. These are like navigation commands but they 45 | -- don't become selection commands when combined with SHIFT. 46 | key_bind ("Ctrl-Alt-g", "move-goto-column") 47 | key_bind ("Alt-g", "move-goto-line") 48 | 49 | -- Selection 50 | -- select-other-end 51 | key_bind ("Ctrl-@", "edit-select-toggle") 52 | 53 | -- Save 54 | key_bind ("Alt-s", "file-save") 55 | -- Suspend 56 | key_bind ("Ctrl-z", "file-suspend") 57 | -- Quit 58 | key_bind ("Ctrl-Alt-q", "file-quit") 59 | 60 | -- Undo 61 | key_bind ("Ctrl-_", "edit-undo") 62 | -- Cut selection to clipboard 63 | key_bind ("Ctrl-w", "edit-cut") 64 | key_bind ("Alt-d", "edit-delete-word") 65 | -- Copy selection to clipboard 66 | key_bind ("Alt-w", "edit-copy") 67 | -- Delete without modifying clipboard 68 | key_bind ("Backspace", "edit-delete-previous-character") 69 | key_bind ("Ctrl-d", "edit-delete-next-character") 70 | key_bind ("Delete", "edit-delete-next-character") 71 | key_bind ("Alt-\\", "edit-delete-horizontal-space") 72 | -- Paste 73 | key_bind ("Ctrl-y", "edit-paste") 74 | 75 | -- Search 76 | key_bind ("Ctrl-s", "edit-find") 77 | key_bind ("Ctrl-r", "edit-find-backward") 78 | key_bind ("Alt-%", "edit-replace") 79 | 80 | -- Insert special characters 81 | key_bind ("Ctrl-j", "edit-insert-newline") 82 | key_bind ("Return", "edit-insert-newline-and-indent") 83 | key_bind ("Tab", "edit-indent-relative") 84 | key_bind ("Ctrl-q", "edit-insert-quoted") 85 | key_bind ("Alt-i", "edit-indent") 86 | 87 | -- Macros 88 | key_bind ("Alt-(", "macro-record") 89 | key_bind ("Alt-)", "macro-stop") 90 | key_bind ("Alt-e", "macro-play") 91 | -------------------------------------------------------------------------------- /zee/eval.lua: -------------------------------------------------------------------------------- 1 | -- User commands 2 | -- 3 | -- Copyright (c) 2009-2016 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program; see the file COPYING. If not, write to the 19 | -- Free Software Foundation, Fifth Floor, 51 Franklin Street, Boston, 20 | -- MA 02111-1301, USA. 21 | 22 | 23 | -- User things 24 | env = {} 25 | 26 | -- Turn texinfo markup into plain text 27 | local function texi (s) 28 | s = s:gsub ("@i{([^}]+)}", function (s) return s:upper () end) 29 | s = s:gsub ("@kbd{([^}]+)}", "%1") -- FIXME: look up binding of command 30 | return s 31 | end 32 | 33 | function Define (name, doc, value) 34 | env[name] = { 35 | doc = texi (doc:chomp ()), 36 | val = value, 37 | } 38 | end 39 | 40 | function get_doc (name) 41 | if command_exists (name) then 42 | return env[name].doc 43 | elseif env[name] and env[name].doc then 44 | return (string.format ("%s is a variable.\n\nIts value is %s\n\n%s", 45 | name, get_variable (name), env[name].doc)) 46 | end 47 | end 48 | 49 | function execute_command (name, ...) 50 | return command_exists (name) and env[name].val (...) 51 | end 52 | 53 | local function loadchunk (func, err) 54 | if func == nil then 55 | minibuf_error (string.format ("Error evaluating Lua: %s", err)) 56 | return true 57 | end 58 | return func () 59 | end 60 | 61 | Define ("eval", 62 | [[ 63 | Evaluate a Lua chunk CHUNK. 64 | ]], 65 | function (chunk) 66 | return loadchunk (load (chunk)) 67 | end 68 | ) 69 | 70 | Define ("load", 71 | [[ 72 | Load and evaluate a Lua chunk from FILE. 73 | ]], 74 | function (file) 75 | return loadchunk (loadfile (file)) 76 | end 77 | ) 78 | 79 | function command_exists (c) 80 | return env[c] and type (env[c].val) == "function" 81 | end 82 | 83 | 84 | -- FIXME: Make this non-interactive: need to change Define so it 85 | -- defines functions in _G, and hence can accept non-interactive 86 | -- functions (which still need documentation, but should not appear in 87 | -- menu). 88 | Define ("execute-command", 89 | [[ 90 | Read command name, then run it. 91 | ]], 92 | function () 93 | local name = minibuf_read_completion ("Command: ", 94 | completion_new (filter (function (e) 95 | return command_exists (e) 96 | end, 97 | std.ielems, table.keys (env))), 98 | "command") 99 | if name == "" then 100 | return true 101 | end 102 | return execute_command (name) 103 | end 104 | ) 105 | -------------------------------------------------------------------------------- /zee/file.lua: -------------------------------------------------------------------------------- 1 | -- Disk file handling 2 | -- 3 | -- Copyright (c) 2009-2014 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | -- FIXME: Reload when file changes on disk 21 | 22 | function exist_file (filename) 23 | if posix.stat (filename) then 24 | return true 25 | end 26 | local _, err = posix.errno () 27 | return err ~= posix.ENOENT 28 | end 29 | 30 | local function is_regular_file (filename) 31 | local st = posix.stat (filename) 32 | return st and st.type == "regular" 33 | end 34 | 35 | -- Return nonzero if file exists and can be written. 36 | local function check_writable (filename) 37 | local ok = posix.euidaccess (filename, "w") 38 | return ok and ok >= 0 39 | end 40 | 41 | -- Write buffer to given file name with given mode. 42 | alien.default.write:types ("ptrdiff_t", "int", "pointer", "size_t") 43 | local function write_file (filename, mode) 44 | local h = posix.creat (filename, mode) 45 | if h then 46 | local s = get_buffer_pre_cursor (buf) 47 | local ret = alien.default.write (h, s.buf.buffer:topointer (), #s) 48 | if ret == #s then 49 | s = get_buffer_post_cursor (buf) 50 | ret = alien.default.write (h, s.buf.buffer:topointer (), #s) 51 | if ret == #s then 52 | ret = true 53 | end 54 | end 55 | 56 | local ret2 = posix.close (h) 57 | if ret == true and ret2 ~= 0 then -- writing error takes precedence over closing error 58 | ret = ret2 59 | end 60 | 61 | return ret 62 | end 63 | end 64 | 65 | Define ("file-save", 66 | [[ 67 | Save buffer in visited file. 68 | ]], 69 | function () 70 | local ret = write_file (buf.filename, "rw-rw-rw-") 71 | if not ret then 72 | return minibuf_error (string.format ("Error writing `%s'%s", buf.filename, 73 | ret == -1 and ": " .. posix.errno () or "")) 74 | end 75 | 76 | minibuf_write ("Wrote " .. buf.filename) 77 | buf.modified = false 78 | undo_set_unchanged (buf.last_undo) 79 | end 80 | ) 81 | 82 | Define ("file-quit", 83 | [[ 84 | Quit, unless there are unsaved changes. 85 | ]], 86 | function () 87 | if buf.modified then 88 | return minibuf_error ("Unsaved changes: use `file-save' or `edit-revert'") 89 | end 90 | 91 | thisflag.quit = true 92 | end 93 | ) 94 | 95 | alien.default.read:types ("ptrdiff_t", "int", "pointer", "size_t") 96 | function read_file (filename) 97 | buf = buffer_new () 98 | local len = posix.stat (filename, "size") 99 | local h = posix.open (filename, posix.O_RDONLY) 100 | if h and len then 101 | buf.text = AStr (len) 102 | if alien.default.read (h, buf.text:topointer (), len) == len then 103 | buf.filename = filename 104 | buf.readonly = not check_writable (filename) 105 | end 106 | posix.close (h) 107 | end 108 | if not buf.filename then 109 | return minibuf_error (string.format ("Error reading file `%s': %s", filename, posix.errno ())) 110 | end 111 | end 112 | 113 | -- Function called on unexpected error or crash (SIGSEGV). 114 | -- Attempts to save modified buffer. 115 | -- If doabort is true, aborts to allow core dump generation; 116 | -- otherwise, exit. 117 | function editor_exit (doabort) 118 | io.stderr:write ("Trying to save buffer (if modified)...\r\n") 119 | 120 | if buf and buf.modified then 121 | local file = buf.filename .. string.upper (PACKAGE) .. "SAVE" 122 | io.stderr:write (string.format ("Saving %s...\r\n", file)) 123 | write_file (file, "rw-------") 124 | end 125 | 126 | term_close () 127 | if doabort then 128 | posix.abort () 129 | else 130 | posix._exit (2) 131 | end 132 | end 133 | 134 | Define ("file-suspend", 135 | [[ 136 | Stop editor and return to superior process. 137 | ]], 138 | function () 139 | posix.raise (posix.SIGTSTP) 140 | end 141 | ) 142 | 143 | -- Signal an error, and abort any ongoing macro definition. 144 | function ding () 145 | if thisflag.defining_macro then 146 | cancel_macro_definition () 147 | end 148 | 149 | if win then 150 | term_beep () 151 | end 152 | -- enable call chaining with `return ding ()' 153 | return true 154 | end 155 | -------------------------------------------------------------------------------- /zee/getkey.lua: -------------------------------------------------------------------------------- 1 | -- Getting and ungetting key strokes 2 | -- 3 | -- Copyright (c) 2010-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | -- Maximum time to avoid screen updates when catching up with buffered 21 | -- input, in milliseconds. 22 | local MAX_RESYNC_MS = 500 23 | 24 | local _last_key 25 | 26 | -- Return last key pressed 27 | function lastkey () 28 | return _last_key 29 | end 30 | 31 | -- Get a keystroke, waiting for up to delay ms, and translate it into a 32 | -- keycode. 33 | local function getkeystroke (delay) 34 | _last_key = term_getkey (delay) 35 | 36 | if _last_key and thisflag.defining_macro then 37 | add_key_to_macro (_last_key) 38 | end 39 | 40 | return _last_key 41 | end 42 | 43 | -- Return the next keystroke, refreshing the screen only when the input 44 | -- buffer is empty, or MAX_RESYNC_MS have elapsed since the last 45 | -- screen refresh. 46 | local next_refresh = {} 47 | local refresh_wait = { 48 | sec = math.floor (MAX_RESYNC_MS / 1000), 49 | usec = (MAX_RESYNC_MS % 1000) * 1000, 50 | } 51 | 52 | local function getkey (delay, norefresh) 53 | local now = posix.gettimeofday () 54 | local keycode = getkeystroke (0) 55 | 56 | if not norefresh and (not keycode or posix.timercmp (now, next_refresh) >= 0) then 57 | term_display () 58 | term_refresh () 59 | next_refresh = posix.timeradd (now, refresh_wait) 60 | end 61 | 62 | if not keycode then 63 | keycode = getkeystroke (delay) 64 | end 65 | 66 | return keycode 67 | end 68 | 69 | function getkey_unfiltered (delay) 70 | local c = term_getkey_unfiltered (delay) 71 | _last_key = c 72 | if thisflag.defining_macro then 73 | add_key_to_macro (c) 74 | end 75 | return c 76 | end 77 | 78 | -- Wait for GETKEY_DELAYED ms or until a key is pressed. 79 | -- The key is then available with getkey. 80 | function waitkey () 81 | ungetkey (getkey (GETKEY_DELAYED)) 82 | end 83 | 84 | -- Unget a key as if it had not been fetched. 85 | function ungetkey (key) 86 | term_ungetkey (key) 87 | 88 | if thisflag.defining_macro then 89 | remove_key_from_macro () 90 | end 91 | end 92 | 93 | -- Get a key chord from the keyboard. 94 | function get_key_chord (norefresh) 95 | return getkey (GETKEY_DEFAULT, norefresh) or get_key_chord (norefresh) 96 | end 97 | -------------------------------------------------------------------------------- /zee/help.lua: -------------------------------------------------------------------------------- 1 | -- Self documentation facility functions 2 | -- 3 | -- Copyright (c) 2010-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | Define ("help-thing", 21 | [[ 22 | Display the help for the given command or variable. 23 | ]], 24 | function (name) 25 | name = name or (interactive () and 26 | minibuf_read_completion ("Describe command or variable: ", 27 | completion_new (table.keys (env)), "thing")) 28 | if name == "" then 29 | return true 30 | end 31 | 32 | local where = "" 33 | if command_exists (name) then 34 | local keys = command_to_binding (name) 35 | if #keys > 0 then 36 | where = string.format ("\n\nBound to: %s", table.concat (keys, ", ")) 37 | end 38 | end 39 | 40 | local doc = get_doc (name) or "No help available" 41 | popup_set (string.format ("Help for `%s':\n\n%s%s", name, doc, where)) 42 | end 43 | ) 44 | 45 | Define ("help-key", 46 | [[ 47 | Display the command invoked by a key combination. 48 | ]], 49 | function (keystr) 50 | local key 51 | if keystr then 52 | key = keycode (keystr) 53 | else 54 | minibuf_write ("Describe key: ") 55 | key = get_key_chord (true) 56 | end 57 | if key then 58 | local name = binding_to_command (key) 59 | local binding = tostring (key) 60 | if not name then 61 | return minibuf_error (binding .. " is undefined") 62 | end 63 | local doc = get_doc (name) 64 | if doc then 65 | popup_set (string.format ("%s runs the command `%s'.\n%s", binding, name, doc)) 66 | end 67 | end 68 | end 69 | ) 70 | -------------------------------------------------------------------------------- /zee/init.lua.in: -------------------------------------------------------------------------------- 1 | std = require "std".barrel () 2 | set = require "std.set" 3 | functional = require "std.functional" 4 | list = require "std.list" 5 | tree = require "std.tree" 6 | posix = require "posix" 7 | rex_gnu = require "rex_gnu" 8 | alien = require "alien" 9 | curses = require "curses" -- part of luaposix 10 | --require "std.strict" -- optional stdlib module: FIXME get this working again 11 | -------------------------------------------------------------------------------- /zee/keycode.lua: -------------------------------------------------------------------------------- 1 | -- Key encoding and decoding functions 2 | -- 3 | -- Copyright (c) 2010-2015 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | 21 | -- Map of key names to code. 22 | local KBD_NONPRINT = 283 23 | local keynametocode = {} 24 | 25 | local non_modifier_name = set { 26 | "Backspace", "Delete", "Down", "End", "F1", "F10", "F11", "F12", 27 | "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "Home", "Insert", 28 | "Left", "PageDown", "PageUp", "Return", "Right", "Tab", "Up", 29 | "Space", "Escape" 30 | } 31 | local modifier_name = set {"Ctrl-", "Alt-"} 32 | 33 | for i in set.elems (non_modifier_name) do 34 | keynametocode[i] = KBD_NONPRINT 35 | end 36 | keynametocode["Space"] = string.byte (' ') 37 | 38 | for i = 0x0, 0x7f do 39 | if posix.isprint (string.char (i)) and i ~= string.byte ('\\') then 40 | keynametocode[string.char (i)] = i 41 | end 42 | end 43 | 44 | -- Array of key names 45 | local keyname = set.union (modifier_name, non_modifier_name) 46 | 47 | -- Insert printable characters in the ASCII range. 48 | for i = 0, 0x7f do 49 | if posix.isprint (string.char (i)) then 50 | set.insert (keyname, string.char (i)) 51 | end 52 | end 53 | 54 | local function normalize_modifier (mod) 55 | return mod:sub (1, 1):upper () .. mod:sub (2, -2):lower () 56 | end 57 | 58 | -- A key code has one `key' and some optional modifiers. 59 | -- For comparisons to work, keycodes are immutable atoms. 60 | local keycode_mt = { 61 | -- Output the write syntax for this keycode (e.g. Ctrl-Alt-F1). 62 | __tostring = function (self) 63 | if not self then 64 | return "invalid keycode: nil" 65 | end 66 | 67 | local s = (self.CTRL and "Ctrl-" or "") .. (self.ALT and "Alt-" or "") 68 | 69 | if not self.key then 70 | return "invalid keycode: " .. s .. "nil" 71 | end 72 | 73 | return s .. self.key 74 | end, 75 | 76 | -- Normalise modifier lookups to capitalized & sans `-' suffix. 77 | -- hasmodifier = keycode.ALT or keycode["c"] 78 | __index = function (self, mod) 79 | mod = normalize_modifier (mod) 80 | return rawget (self, mod) 81 | end, 82 | 83 | -- Return the immutable atom for this keycode with modifier added. 84 | -- ctrlkey = "Ctrl-" + key 85 | __add = function (self, mod) 86 | if "string" == type (self) then mod, self = self, mod end 87 | mod = normalize_modifier (mod) 88 | if self[mod] then return self end 89 | return keycode (mod .. "-" .. tostring (self)) 90 | end, 91 | 92 | -- Return the immutable atom for this keycode with modifier removed. 93 | -- withoutmeta = key - "Alt-" 94 | __sub = function (self, mod) 95 | if "string" == type (self) then mod, self = self, mod end 96 | mod = normalize_modifier (mod) 97 | local keystr = tostring (self):gsub (mod .. "%-", "") 98 | return keycode (keystr) 99 | end, 100 | } 101 | 102 | -- Extract a modifier prefix of a key string. 103 | local function getmodifier (s) 104 | for match in set.elems (modifier_name) do 105 | if match == s:sub (1, #match) then 106 | return match, s:sub (#match + 1) 107 | end 108 | end 109 | return nil, s 110 | end 111 | 112 | -- Convert a single keychord string to its key code. 113 | keycode = functional.memoize (function (chord) 114 | local key, tail = setmetatable ({}, keycode_mt), chord 115 | 116 | local mod 117 | repeat 118 | mod, tail = getmodifier (tail) 119 | if mod == "Ctrl-" then 120 | key.CTRL = true 121 | elseif mod == "Alt-" then 122 | key.ALT = true 123 | end 124 | until not mod 125 | if not set.member (keyname, tail) then return nil end 126 | key.key = tail 127 | key.code = keynametocode[tail] 128 | 129 | return key 130 | end) 131 | -------------------------------------------------------------------------------- /zee/macro.lua: -------------------------------------------------------------------------------- 1 | -- Macro facility functions 2 | -- 3 | -- Copyright (c) 2010-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | local macro = {} 21 | 22 | -- FIXME: macros should be executed immediately and abort on error; 23 | -- they should be stored as a macro list, not a series of 24 | -- keystrokes. Macros should return success/failure. 25 | function add_key_to_macro (key) 26 | table.insert (macro, key) 27 | end 28 | 29 | function remove_key_from_macro () 30 | table.remove (macro) 31 | end 32 | 33 | function cancel_macro_definition () 34 | macro = {} 35 | thisflag.defining_macro = false 36 | end 37 | 38 | Define ("macro-record", 39 | [[ 40 | Record subsequent keyboard input, defining a macro. 41 | The commands are recorded even as they are executed. 42 | Use `macro-stop' to finish recording and make the macro available. 43 | ]], 44 | function () 45 | if thisflag.defining_macro then 46 | minibuf_error ("Already defining a keyboard macro") 47 | return true 48 | end 49 | 50 | if macro ~= nil then 51 | cancel_macro_definition () 52 | end 53 | 54 | minibuf_write ("Defining keyboard macro...") 55 | 56 | thisflag.defining_macro = true 57 | macro = {} 58 | end 59 | ) 60 | 61 | Define ("macro-stop", 62 | [[ 63 | Finish defining a keyboard macro. 64 | The definition was started by `macro-record'. 65 | The macro is now available for use via `macro-play'. 66 | ]], 67 | function () 68 | if not thisflag.defining_macro then 69 | minibuf_error ("Not defining a keyboard macro") 70 | return true 71 | end 72 | 73 | thisflag.defining_macro = false 74 | end 75 | ) 76 | 77 | local function process_keys (keys) 78 | local cur = term_buf_len () 79 | 80 | for i = #keys, 1, -1 do 81 | term_ungetkey (keys[i]) 82 | end 83 | 84 | undo_start_sequence () 85 | while term_buf_len () > cur do 86 | get_and_run_command () 87 | end 88 | undo_end_sequence () 89 | end 90 | 91 | Define ("macro-play", 92 | [[ 93 | Play back the last macro that you defined. 94 | ]], 95 | function (...) 96 | local m = {...} 97 | if #m > 0 then 98 | m = functional.map (keycode, std.ielems, m) 99 | elseif interactive () then 100 | m = macro 101 | if m == nil then 102 | minibuf_error ("No macro has been defined") 103 | return true 104 | end 105 | end 106 | 107 | process_keys (m) 108 | end 109 | ) 110 | -------------------------------------------------------------------------------- /zee/main.lua: -------------------------------------------------------------------------------- 1 | -- Program invocation, startup and shutdown 2 | -- 3 | -- Copyright (c) 2010-2015 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | -- Derived constants 21 | VERSION_STRING = PACKAGE_NAME .. " " .. VERSION 22 | 23 | local COPYRIGHT_STRING = "" 24 | 25 | local program_name = posix.basename (arg[0] or PACKAGE) 26 | spec = program_name .. " " .. VERSION .. [[ 27 | 28 | Copyright (C) 2015 Free Software Foundation, Inc. 29 | ]] .. PACKAGE_NAME .. " comes with ABSOLUTELY NO WARRANTY." .. [[ 30 | 31 | You may redistribute copies of ]] .. PACKAGE_NAME .. [[ 32 | 33 | 34 | under the terms of the GNU General Public License. 35 | For more information about these matters, see the file named COPYING. 36 | 37 | Usage: ]] .. program_name .. [[ 38 | 39 | 40 | An editor. 41 | 42 | Exit status is 0 if OK, 1 if it cannot start up, for example because 43 | of an invalid command-line argument, and 2 if it crashes or runs out 44 | of memory. 45 | 46 | ~/.]] .. PACKAGE .. [[ is the user init file 47 | 48 | -q, --no-init-file do not load ~/.]] .. PACKAGE .. [[ 49 | 50 | -e, --eval=CHUNK evaluate Lua chunk CHUNK 51 | -n, --line=LINE start editing at line LINE 52 | --version display version information, then exit 53 | --help display this help, then exit 54 | 55 | Please report bugs at ]] .. PACKAGE_BUGREPORT .. [[ 56 | ]] 57 | -- -b, --batch run non-interactively 58 | 59 | 60 | -- Runtime constants 61 | 62 | -- Display attributes 63 | display = {} 64 | 65 | -- Keyboard handling 66 | 67 | GETKEY_DEFAULT = -1 68 | GETKEY_DELAYED = 2000 69 | 70 | 71 | -- Global flags, stored in thisflag and lastflag. 72 | -- need_resync: a resync is required. 73 | -- quit: the user has asked to quit. 74 | -- defining_macro: we are defining a macro. 75 | 76 | 77 | -- The current window 78 | win = nil 79 | 80 | -- The current buffer 81 | buf = nil 82 | 83 | -- The global editor flags. 84 | thisflag = {} 85 | lastflag = {} 86 | 87 | 88 | local function segv_sig_handler (signo) 89 | io.stderr:write (prog.name .. ": " .. PACKAGE_NAME .. 90 | " crashed. Please send a bug report to <" .. 91 | PACKAGE_BUGREPORT .. ">.\r\n") 92 | editor_exit (true) 93 | end 94 | 95 | local function other_sig_handler (signo) 96 | local msg = progran_name .. ": terminated with signal " .. signo .. ".\n" .. debug.traceback () 97 | io.stderr:write (msg:gsub ("\n", "\r\n")) 98 | editor_exit (false) 99 | end 100 | 101 | local function signal_init () 102 | -- Set up signal handling 103 | posix.signal(posix.SIGSEGV, segv_sig_handler) 104 | posix.signal(posix.SIGBUS, segv_sig_handler) 105 | posix.signal(posix.SIGHUP, other_sig_handler) 106 | posix.signal(posix.SIGINT, other_sig_handler) 107 | posix.signal(posix.SIGTERM, other_sig_handler) 108 | end 109 | 110 | function main () 111 | signal_init () 112 | local OptionParser = require "std.optparse" 113 | local parser = OptionParser (spec) 114 | _G.arg, _G.opts = parser:parse (_G.arg) 115 | 116 | if #arg ~= 1 and not (#arg == 0 and opts.eval) then 117 | parser:opterr ("Need a file or expression") 118 | end 119 | 120 | os.setlocale ("") 121 | win = {} 122 | 123 | local w, h = term_width (), term_height () 124 | win = {topdelta = 0, start_column = 0, last_line = 0} 125 | win.fwidth = 2 126 | term_init () 127 | resize_window () 128 | 129 | if not opts.no_init_file then 130 | local s = os.getenv ("HOME") 131 | if s then 132 | execute_command ("load", s .. "/." .. PACKAGE) 133 | end 134 | end 135 | 136 | -- Load file 137 | local ok = true 138 | if #arg == 1 then 139 | ok = not read_file (arg[1]) 140 | if ok then 141 | execute_command ("move-goto-line", opts.line or 1) 142 | end 143 | end 144 | 145 | -- Evaluate Lua chunks given on the command line. 146 | if type (opts.eval) == "string" then -- If only one argument, put it in a table 147 | opts.eval = {opts.eval} 148 | end 149 | for _, c in ipairs (opts.eval or {}) do 150 | if execute_command ("eval", c) then 151 | break 152 | end 153 | if thisflag.quit then 154 | break 155 | end 156 | end 157 | 158 | if ok and #arg == 1 then 159 | lastflag.need_resync = true 160 | 161 | -- Refresh minibuffer in case there's a pending error message. 162 | minibuf_refresh () 163 | 164 | -- Leave cursor in correct position. 165 | term_redraw_cursor () 166 | 167 | -- Run the main loop. 168 | while not thisflag.quit do 169 | if lastflag.need_resync then 170 | window_resync (win) 171 | end 172 | get_and_run_command () 173 | end 174 | end 175 | 176 | -- Tidy and close the terminal. 177 | term_finish () 178 | 179 | -- Print any error message. 180 | if not ok then 181 | io.stderr:write (minibuf_contents .. "\n") 182 | end 183 | -- FIXME: Add startup banner (how to quit and get menu) 184 | end 185 | -------------------------------------------------------------------------------- /zee/minibuf.lua: -------------------------------------------------------------------------------- 1 | -- Minibuffer 2 | -- 3 | -- Copyright (c) 2010-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | local function term_minibuf_write (s) 21 | end 22 | 23 | -- FIXME: Turn minibuf_read inside out so it's a minor mode 24 | -- Read a string from the minibuffer. 25 | function minibuf_read (prompt, cp) 26 | local quit, value, pos = false, "", 0 27 | 28 | -- FIXME: Stop these definitions appearing in global environment 29 | -- (Have nested environments) 30 | Define ("minibuf-insert-character", "", 31 | function () 32 | local key = term_keytobyte (lastkey ()) 33 | if not key then 34 | ding () 35 | return true 36 | end 37 | value = value:sub (1, pos) .. string.char (key) .. value:sub (pos + 1) 38 | pos = pos + 1 39 | end) 40 | 41 | Define ("minibuf-exit", "", 42 | function () 43 | quit = true 44 | end) 45 | 46 | Define ("minibuf-quit", "", 47 | function () 48 | value = "" 49 | quit = true 50 | end) 51 | 52 | Define ("minibuf-move-start-line", "", 53 | function () 54 | pos = 0 55 | end) 56 | 57 | Define ("minibuf-move-end-line", "", 58 | function () 59 | pos = #value 60 | end) 61 | 62 | Define ("minibuf-move-previous-character", "", 63 | function () 64 | if pos > 0 then 65 | pos = pos - 1 66 | else 67 | ding () 68 | end 69 | end) 70 | 71 | Define ("minibuf-move-next-character", "", 72 | function () 73 | if pos < #value then 74 | pos = pos + 1 75 | else 76 | ding () 77 | end 78 | end) 79 | 80 | Define ("minibuf-delete-previous-character", "", 81 | function () 82 | if pos > 0 then 83 | value = value:sub (1, pos - 1) .. value:sub (pos + 1) 84 | pos = pos - 1 85 | else 86 | ding () 87 | end 88 | end) 89 | 90 | Define ("minibuf-delete-next-character", "", 91 | function () 92 | if pos < #value then 93 | value = value:sub (1, pos) .. value:sub (pos + 2) 94 | else 95 | ding () 96 | end 97 | end) 98 | 99 | Define ("minibuf-previous-page", "", 100 | function () 101 | if cp == nil then 102 | ding () 103 | else 104 | popup_scroll_down () 105 | end 106 | end) 107 | 108 | Define ("minibuf-next-page", "", 109 | function () 110 | if cp == nil then 111 | ding () 112 | else 113 | popup_scroll_up () 114 | end 115 | end) 116 | 117 | Define ("minibuf-complete", "", 118 | function () 119 | if not cp or #cp.matches == 0 then 120 | ding () 121 | else 122 | if value ~= cp.match then 123 | value = cp.match 124 | pos = #value 125 | else 126 | popup_scroll_down_and_loop () 127 | end 128 | end 129 | end) 130 | 131 | local minibuf_bindings = {} 132 | bindings = minibuf_bindings 133 | bind_printing_chars ("minibuf-insert-character") 134 | key_bind ("Return", "minibuf-exit") 135 | key_bind ("Ctrl-Alt-z", "file-suspend") 136 | key_bind ("Ctrl-g", "minibuf-quit") 137 | key_bind ("Home", "minibuf-move-start-line") 138 | key_bind ("End", "minibuf-move-end-line") 139 | key_bind ("Left", "minibuf-move-previous-character") 140 | key_bind ("Right", "minibuf-move-next-character") 141 | key_bind ("Backspace", "minibuf-delete-previous-character") 142 | key_bind ("Ctrl-?", "minibuf-delete-previous-character") 143 | key_bind ("Delete", "minibuf-delete-next-character") 144 | key_bind ("PageUp", "minibuf-previous-page") 145 | key_bind ("PageDown", "minibuf-next-page") 146 | key_bind ("Tab", "minibuf-complete") 147 | 148 | local saved 149 | repeat 150 | if cp then 151 | completion_try (cp, value) 152 | popup_completion (cp) 153 | end 154 | 155 | minibuf_write (prompt) 156 | minibuf_refresh () 157 | 158 | local w, h = term_width (), term_height () 159 | local margin = 1 160 | local n = 0 161 | 162 | if #prompt + pos + 1 >= w then 163 | margin = margin + 1 164 | term_addstr ('$') 165 | n = pos - pos % (w - #prompt - 2) 166 | end 167 | 168 | term_addstr (value:sub (n + 1, math.min (w - #prompt - margin, #value - n))) 169 | 170 | if #value - n >= w - #prompt - margin then 171 | term_move (h - 1, w - 1) 172 | term_addstr ('$') 173 | end 174 | 175 | term_move (h - 1, #prompt + margin - 1 + pos % (w - #prompt - margin)) 176 | term_refresh () 177 | 178 | local key = get_key_chord (true) 179 | local name = binding_to_command (key) 180 | if command_exists (name) then 181 | call_command (name) 182 | else 183 | ding () 184 | end 185 | until quit 186 | 187 | minibuf_clear () 188 | if cp then 189 | popup_clear () 190 | term_display () 191 | end 192 | bindings = root_bindings 193 | return value 194 | end 195 | 196 | 197 | -- Minibuffer wrapper functions. 198 | 199 | minibuf_contents = nil 200 | 201 | function minibuf_refresh () 202 | if win then 203 | if minibuf_contents then 204 | term_move (term_height () - 1, 0) 205 | term_clrtoeol () 206 | term_addstr (minibuf_contents:sub (1, math.min (#minibuf_contents, term_width ()))) 207 | end 208 | term_refresh () 209 | end 210 | end 211 | 212 | -- Clear the minibuffer. 213 | function minibuf_clear () 214 | minibuf_write ("") 215 | end 216 | 217 | -- Write the specified string in the minibuffer. 218 | function minibuf_write (s) 219 | if s ~= minibuf_contents then 220 | minibuf_contents = s 221 | minibuf_refresh () 222 | end 223 | end 224 | 225 | -- Write the specified error string in the minibuffer and signal an error. 226 | function minibuf_error (s) 227 | minibuf_write (s) 228 | return ding () 229 | end 230 | 231 | -- Read a string from the minibuffer using a completion. 232 | function minibuf_read_completion (fmt, cp, class_name) 233 | while true do 234 | local ms = minibuf_read (fmt, cp) 235 | if ms == "" then -- Cancelled. 236 | ding () 237 | return nil 238 | else 239 | -- Complete partial words if possible. 240 | if completion_try (cp, ms) then 241 | ms = cp.match 242 | end 243 | 244 | if set.member (cp.completions, ms) then 245 | minibuf_clear () 246 | return ms 247 | else 248 | minibuf_error (string.format ("There is no " .. class_name .. " named `%s'", ms)) 249 | waitkey () 250 | end 251 | end 252 | end 253 | end 254 | 255 | -- Read a non-negative number from the minibuffer. 256 | function minibuf_read_number (prompt) 257 | local n 258 | repeat 259 | local ms = minibuf_read (prompt) 260 | if not ms then 261 | return ding () 262 | else 263 | n = tonumber (ms, 10) 264 | end 265 | if not n then 266 | minibuf_write ("Please enter a number.") 267 | end 268 | until n 269 | 270 | return n 271 | end 272 | -------------------------------------------------------------------------------- /zee/move.lua: -------------------------------------------------------------------------------- 1 | -- Movement commands 2 | -- 3 | -- Copyright (c) 2010-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | Define ("move-start-line", 21 | [[ 22 | Move the cursor to the beginning of the line. 23 | ]], 24 | function () 25 | goto_offset (get_buffer_line_o (buf)) 26 | set_goalc (0) 27 | end 28 | ) 29 | 30 | Define ("move-start-line-text", 31 | [[ 32 | Move the cursor to the first non-whitespace character on this line. 33 | ]], 34 | function () 35 | goto_offset (get_buffer_line_o (buf)) 36 | while not end_of_line () and following_char ():match ("%s") do 37 | move_char (1) 38 | end 39 | end 40 | ) 41 | 42 | Define ("move-end-line", 43 | [[ 44 | Move the cursor to the end of the line. 45 | ]], 46 | function () 47 | goto_offset (get_buffer_line_o (buf) + buffer_line_len (buf)) 48 | set_goalc (math.huge) 49 | end 50 | ) 51 | 52 | Define ("move-previous-character", 53 | [[ 54 | Move the cursor left one character. 55 | ]], 56 | function () 57 | return not move_char (-1) 58 | end 59 | ) 60 | 61 | Define ("move-next-character", 62 | [[ 63 | Move the cursor right one character. 64 | ]], 65 | function () 66 | return not move_char (1) 67 | end 68 | ) 69 | 70 | Define ("move-previous-line", 71 | [[ 72 | Move cursor vertically up one line. 73 | If there is no character in the target line exactly over the current column, 74 | the cursor is positioned after the character in that line which spans this 75 | column, or at the end of the line if it is not long enough. 76 | ]], 77 | function () 78 | return move_line (-1) 79 | end 80 | ) 81 | 82 | Define ("move-next-line", 83 | [[ 84 | Move cursor vertically down one line. 85 | If there is no character in the target line exactly under the current column, 86 | the cursor is positioned after the character in that line which spans this 87 | column, or at the end of the line if it is not long enough. 88 | ]], 89 | function () 90 | return move_line (1) 91 | end 92 | ) 93 | 94 | Define ("move-start-file", 95 | [[ 96 | Move the cursor to the beginning of the file. 97 | ]], 98 | function () 99 | goto_offset (1) 100 | end 101 | ) 102 | 103 | Define ("move-end-file", 104 | [[ 105 | Move the cursor to the end of the file. 106 | ]], 107 | function () 108 | goto_offset (get_buffer_size (buf) + 1) 109 | end 110 | ) 111 | 112 | Define ("move-previous-page", 113 | [[ 114 | Scroll text of current window downward near full screen. 115 | ]], 116 | function () 117 | return move_line (-win.eheight) 118 | end 119 | ) 120 | 121 | Define ("move-next-page", 122 | [[ 123 | Scroll text of current window upward near full screen. 124 | ]], 125 | function () 126 | return move_line (win.eheight) 127 | end 128 | ) 129 | 130 | -- Move through words 131 | local function move_word (dir) 132 | local gotword = false 133 | repeat 134 | while not (dir > 0 and end_of_line or beginning_of_line) () do 135 | if get_buffer_char (buf, get_buffer_pt (buf) - (dir < 0 and 1 or 0)):match ("%w") then 136 | gotword = true 137 | elseif gotword then 138 | break 139 | end 140 | move_char (dir) 141 | end 142 | until gotword or not move_char (dir) 143 | return gotword 144 | end 145 | 146 | Define ("move-next-word", 147 | [[ 148 | Move the cursor forward one word. 149 | ]], 150 | function () 151 | return not move_word (1) 152 | end 153 | ) 154 | 155 | Define ("move-previous-word", 156 | [[ 157 | Move the cursor backwards one word. 158 | ]], 159 | function () 160 | return not move_word (-1) 161 | end 162 | ) 163 | 164 | local function move_paragraph (dir, line_extremum) 165 | repeat until not is_empty_line () or move_line (dir) 166 | repeat until is_empty_line () or move_line (dir) 167 | 168 | if is_empty_line () then 169 | execute_command ("move-start-line") 170 | else 171 | execute_command (line_extremum) 172 | end 173 | end 174 | 175 | Define ("move-previous-paragraph", 176 | [[ 177 | Move the cursor backward to the start of the paragraph. 178 | ]], 179 | function () 180 | move_paragraph (-1, "move-start-line") 181 | end 182 | ) 183 | 184 | Define ("move-next-paragraph", 185 | [[ 186 | Move the cursor forward to the end of the paragraph. 187 | ]], 188 | function () 189 | move_paragraph (1, "move-end-line") 190 | end 191 | ) 192 | 193 | Define ("move-goto-character", 194 | [[ 195 | Move to character @i{position}. Beginning of buffer is character 1. 196 | ]], 197 | function (n) 198 | n = tonumber (n) 199 | if not n and interactive () then 200 | n = minibuf_read_number ("Goto char: ") 201 | end 202 | if type (n) ~= "number" then 203 | return true 204 | end 205 | 206 | goto_offset (math.min (get_buffer_size (buf) + 1, math.max (n, 1))) 207 | end 208 | ) 209 | 210 | Define ("move-goto-line", 211 | [[ 212 | Move the cursor to the given line. 213 | Line 1 is the beginning of the buffer. 214 | ]], 215 | function (n) 216 | n = tonumber (n) 217 | if not n and interactive () then 218 | n = minibuf_read_number ("Goto line: ") 219 | end 220 | if type (n) ~= "number" then 221 | return true 222 | end 223 | 224 | move_line ((math.max (n, 1) - 1) - get_buffer_line (buf)) 225 | execute_command ("move-start-line") 226 | end 227 | ) 228 | 229 | -- FIXME: Abstract out the interactive input of arguments à la C Zee 230 | Define ("move-goto-column", 231 | [[ 232 | Move the cursor to the given column. 233 | ]], 234 | function (n) 235 | n = tonumber (n) 236 | if not n and interactive () then 237 | n = minibuf_read_number ("Goto column: ") 238 | end 239 | if type (n) ~= "number" then 240 | return true 241 | end 242 | 243 | goto_offset (math.min (math.max (n, 1), buffer_line_len (buf)) - 1 + get_buffer_line_o (buf)) 244 | end 245 | ) 246 | -------------------------------------------------------------------------------- /zee/search.lua: -------------------------------------------------------------------------------- 1 | -- Search and replace functions 2 | -- 3 | -- Copyright (c) 2010-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | -- Return true if there are no upper-case letters in the given string. 21 | -- If `regex' is true, ignore escaped letters. 22 | local function no_upper (s) 23 | local quote_flag = false 24 | for i = 1, #s do 25 | if s[i] == '\\' then 26 | quote_flag = not quote_flag 27 | elseif not quote_flag and s[i] == s[i]:upper () then 28 | return false 29 | end 30 | end 31 | return true 32 | end 33 | 34 | local re_flags = rex_gnu.flags () 35 | local re_find_err 36 | 37 | local function find_substr (as, s, forward, notbol, noteol, icase) 38 | local ret 39 | local ok, r = pcall (rex_gnu.new, s, bit32.bor (re_flags.SYNTAX_EGREP, icase and re_flags.ICASE or 0)) 40 | if ok then 41 | local ef = 0 42 | if notbol then 43 | ef = bit32.bor (ef, re_flags.not_bol) 44 | end 45 | if noteol then 46 | ef = bit32.bor (ef, re_flags.not_eol) 47 | end 48 | if not forward then 49 | ef = bit32.bor (ef, re_flags.backward) 50 | end 51 | local match_from, match_to = r:find (as, nil, ef) 52 | if match_from then 53 | if forward then 54 | ret = match_to + 1 55 | else 56 | ret = match_from 57 | end 58 | end 59 | else 60 | re_find_err = r 61 | end 62 | 63 | return ret 64 | end 65 | 66 | function regex_match (s, pat) 67 | return find_substr (s, pat, true, false, false, false) ~= nil 68 | end 69 | 70 | local function search (s, forward) 71 | if #s < 1 then 72 | return false 73 | end 74 | 75 | -- Attempt match. 76 | local o = get_buffer_pt (buf) 77 | local notbol = forward and o > 1 78 | local noteol = not forward and o <= get_buffer_size (buf) 79 | local downcase = get_variable ("caseless-search") and no_upper (s) 80 | local as = (forward and get_buffer_post_cursor or get_buffer_pre_cursor) (buf) 81 | local pos = find_substr (as, s, forward, notbol, noteol, downcase) 82 | if not pos then 83 | return false 84 | end 85 | 86 | goto_offset (pos + (forward and (get_buffer_pt (buf) - 1) or 0)) 87 | thisflag.need_resync = true 88 | return true 89 | end 90 | 91 | 92 | -- Incremental search engine. 93 | -- FIXME: Once the search is underway, "find next" is hard-wired to Ctrl-f. 94 | -- Having it hard-wired is obviously broken, but something neutral like Return 95 | -- would be better, or look up current binding of relevant command. 96 | -- The proposed meaning of Escape obviates the current behaviour of Return. 97 | local last_search 98 | local function isearch (forward, pattern) 99 | local old_mark 100 | if buf.mark then 101 | old_mark = copy_marker (buf.mark) 102 | end 103 | 104 | buf.search = true 105 | 106 | local last = true 107 | local start = get_buffer_pt (buf) 108 | local cur = start 109 | while true do 110 | -- Make the minibuf message. 111 | local ms = string.format ("%sI-search%s: %s", 112 | (last and "" or "Failing "), 113 | forward and "" or " backward", 114 | pattern) 115 | 116 | -- Regex error. 117 | if re_find_err then 118 | ms = ms .. string.format (" [%s]", re_find_err) 119 | re_find_err = nil 120 | end 121 | 122 | minibuf_write (ms) 123 | 124 | local c = interactive () and get_key_chord () 125 | 126 | if not c then 127 | elseif c == keycode "Ctrl-g" then 128 | goto_offset (start) 129 | buf.mark = old_mark 130 | ding () 131 | break 132 | elseif c == keycode "BACKSPACE" then 133 | if #pattern > 0 then 134 | pattern = pattern:sub (1, -2) 135 | cur = start 136 | goto_offset (start) 137 | else 138 | ding () 139 | end 140 | elseif c == keycode "Ctrl-Alt-q" then 141 | minibuf_write (string.format ("%s^Q-", ms)) 142 | pattern = pattern .. string.char (getkey_unfiltered (GETKEY_DEFAULT)) 143 | elseif c == keycode "Ctrl-Alt-f" or c == keycode "Ctrl-f" then -- Invert direction. 144 | forward = c == keycode "Ctrl-f" 145 | if #pattern > 0 then -- Find next match. 146 | cur = get_buffer_pt (buf) 147 | last_search = pattern -- Save search string. 148 | elseif last_search then 149 | pattern = last_search 150 | end 151 | elseif c.ALT or c.CTRL or c == keycode "Return" or term_keytobyte (c) == nil then 152 | if #pattern > 0 then 153 | last_search = pattern -- Save search string. 154 | end 155 | if c ~= keycode "Return" then 156 | ungetkey (c) 157 | end 158 | break 159 | else 160 | pattern = pattern .. string.char (term_keytobyte (c)) 161 | end 162 | 163 | if #pattern > 0 then 164 | goto_offset (cur) 165 | last = search (pattern, forward) 166 | if not c then 167 | break 168 | end 169 | else 170 | last = true 171 | end 172 | 173 | window_resync (win) 174 | term_display () 175 | end 176 | 177 | -- done 178 | buf.search = false 179 | 180 | return true 181 | end 182 | 183 | Define ("edit-find", 184 | [[ 185 | Do incremental search forward for regular expression. 186 | As you type characters, they add to the search string and are found. 187 | Type @kbd{Return} to exit, leaving cursor at location found. 188 | Type @kbd{Ctrl-f} to search again forward, @kbd{Ctrl-Alt-f} to search again backward. 189 | @kbd{Ctrl-g} when search is successful aborts and moves cursor to starting 190 | point. 191 | ]], 192 | function (s) 193 | isearch (true, s or "") 194 | end 195 | ) 196 | 197 | Define ("edit-find-backward", 198 | [[ 199 | Do incremental search backward for regular expression. 200 | As you type characters, they add to the search string and are found. 201 | Type @kbd{Return} to exit, leaving cursor at location found. 202 | Type @kbd{Ctrl-Alt-f} to search again backward, @kbd{Ctrl-f} to search again forward. 203 | @kbd{Ctrl-g} when search is successful aborts and moves cursor to starting 204 | point. 205 | ]], 206 | function (s) 207 | isearch (false, s or "") 208 | end 209 | ) 210 | 211 | -- Check the case of a string. 212 | -- Returns "uppercase" if it is all upper case, "capitalized" if just 213 | -- the first letter is, and nil otherwise. 214 | local function check_case (s) 215 | if regex_match (s, "^[[:upper:]]+$") then 216 | return "uppercase" 217 | elseif regex_match (s, "^[[:upper:]][^[:upper:]]*") then 218 | return "capitalized" 219 | end 220 | end 221 | 222 | -- Recase str according to newcase. 223 | local function recase (s, newcase) 224 | local bs = "" 225 | local i, len 226 | 227 | if newcase == "capitalized" or newcase == "upper" then 228 | bs = bs .. s[1]:upper () 229 | else 230 | bs = bs .. s[1]:lower () 231 | end 232 | 233 | for i = 2, #s do 234 | bs = bs .. (newcase == "upper" and string.upper or string.lower) (s[i]) 235 | end 236 | 237 | return bs 238 | end 239 | 240 | -- FIXME: Make edit-replace run on selection. 241 | Define ("edit-replace", 242 | [[ 243 | Replace occurrences of a regular expression with other text. 244 | As each match is found, the user must type a character saying 245 | what to do with it. 246 | ]], 247 | function (find) 248 | local find = find or (interactive () and minibuf_read ("Query replace string: ")) 249 | if not find then 250 | return ding () 251 | end 252 | local find_no_upper = no_upper (find) 253 | 254 | local repl = interactive () and minibuf_read (string.format ("Query replace `%s' with: ", find)) 255 | if repl == "" then 256 | ding () 257 | end 258 | 259 | local noask = false 260 | local count = 0 261 | local ok = true 262 | while search (find, true) do 263 | local c = keycode ' ' 264 | 265 | if not noask then 266 | if thisflag.need_resync then 267 | window_resync (win) 268 | end 269 | minibuf_write (string.format ("Replace `%s' with `%s' (y, n, !, ., q)? ", find, repl)) 270 | c = get_key_chord () 271 | minibuf_clear () 272 | 273 | if c == keycode "q" then -- Quit immediately. 274 | break 275 | elseif c == keycode "Ctrl-g" then 276 | ding () 277 | break 278 | elseif c == keycode "!" then -- Replace all without asking. 279 | noask = true 280 | end 281 | end 282 | 283 | if c == keycode " " or c == keycode "y" or c == keycode "." or c == keycode "!" then 284 | -- Perform replacement. 285 | count = count + 1 286 | local case_repl = repl 287 | local r = region_new (get_buffer_pt (buf) - #find, get_buffer_pt (buf)) 288 | if find_no_upper and get_variable ("case-replace") then 289 | local case_type = check_case (get_buffer_region (buf, r)) 290 | if case_type then 291 | case_repl = recase (repl, case_type) 292 | end 293 | end 294 | local m = cursor_marker () 295 | goto_offset (r.start) 296 | replace_string (#find, case_repl) 297 | goto_offset (m.o) 298 | 299 | if c == keycode "." then -- Replace and quit. 300 | break 301 | end 302 | elseif c ~= keycode "n" and c ~= keycode "Return" and c ~= keycode "Delete" then 303 | ungetkey (c) 304 | ok = false 305 | break 306 | end 307 | end 308 | 309 | if thisflag.need_resync then 310 | window_resync (win) 311 | end 312 | 313 | if ok then 314 | minibuf_write (string.format ("Replaced %d occurrence%s", count, count ~= 1 and "s" or "")) 315 | end 316 | 317 | return not ok 318 | end 319 | ) 320 | -------------------------------------------------------------------------------- /zee/shell.lua: -------------------------------------------------------------------------------- 1 | -- Run shell commands 2 | -- 3 | -- Copyright (c) 2010-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | Define ("edit-shell-command", 21 | [[ 22 | Reads a line of text using the minibuffer and creates an inferior shell 23 | to execute the line as a command; passes the selection as input to the 24 | shell command. 25 | If the shell command produces any output, it is inserted into the 26 | file, replacing the selection if any. 27 | ]], 28 | function (cmd) 29 | if not cmd and interactive () then 30 | cmd = minibuf_read ("Shell command: ") 31 | end 32 | if cmd == "" then 33 | return ding () 34 | end 35 | 36 | local ok = true 37 | 38 | local h, tempfile 39 | if buf.mark then 40 | tempfile = os.tmpname () 41 | 42 | h = io.open (tempfile, "w") 43 | if not h then 44 | ok = minibuf_error ("Cannot open temporary file") 45 | else 46 | local fd = posix.fileno (h) 47 | local s = get_buffer_region (buf, calculate_the_selection ()) 48 | local written, err = alien.default.write (fd, s.buf.buffer:topointer (), #s) 49 | if not written then 50 | ok = minibuf_error ("Error writing to temporary file: " .. err) 51 | end 52 | end 53 | end 54 | 55 | if ok then 56 | local cmdline = string.format ("%s 2>&1%s", cmd, tempfile and " <" .. tempfile or "") 57 | local pipe = io.popen (cmdline, "r") 58 | if not pipe then 59 | ok = minibuf_error ("Cannot open pipe to process") 60 | else 61 | local out = pipe:read ("*a") 62 | pipe:close () 63 | 64 | if #out == 0 then 65 | minibuf_write ("(Shell command succeeded with no output)") 66 | else 67 | local del = 0 68 | if buf.mark then 69 | local r = calculate_the_selection () 70 | goto_offset (r.start) 71 | del = get_region_size (r) 72 | end 73 | replace_string (del, out) 74 | end 75 | end 76 | end 77 | 78 | -- A sub-process may have caught a SIGWINCH, so assume one did. 79 | curses.ungetch (curses.KEY_RESIZE) 80 | 81 | if h then 82 | h:close () 83 | end 84 | if tempfile then 85 | os.remove (tempfile) 86 | end 87 | 88 | return not ok 89 | end 90 | ) 91 | -------------------------------------------------------------------------------- /zee/term.lua: -------------------------------------------------------------------------------- 1 | -- Display engine 2 | -- 3 | -- Copyright (c) 2009-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | -- Window table: 21 | -- { 22 | -- topdelta: top line delta from cursor 23 | -- last_line: last cursor line number 24 | -- fwidth, fheight: actual width and height of the window 25 | -- ewidth, eheight: editing width and height of the window 26 | -- } 27 | 28 | function window_resync (wp) 29 | local n = get_buffer_line (buf) 30 | local delta = n - wp.last_line 31 | 32 | if delta ~= 0 then 33 | if (delta > 0 and wp.topdelta + delta < wp.eheight) or (delta < 0 and wp.topdelta >= -delta) then 34 | wp.topdelta = wp.topdelta + delta 35 | elseif n > wp.eheight / 2 then 36 | wp.topdelta = math.floor (wp.eheight / 2) 37 | else 38 | wp.topdelta = n 39 | end 40 | wp.last_line = n 41 | end 42 | end 43 | 44 | Define ("view-refresh", 45 | [[ 46 | Refresh the display. 47 | ]], 48 | function () 49 | term_clear () 50 | term_display () 51 | term_refresh () 52 | end 53 | ) 54 | 55 | function resize_window () 56 | -- Resize window horizontally. 57 | win.fwidth = term_width () 58 | win.ewidth = win.fwidth 59 | 60 | -- Resize window vertically. 61 | win.fheight = term_height () 62 | win.eheight = win.fheight 63 | win.eheight = win.eheight - math.min (win.eheight, 2) 64 | end 65 | 66 | -- Tidy up the term ready to exit (temporarily or permanently!). 67 | function term_tidy () 68 | term_move (term_height () - 1, 0) 69 | term_clrtoeol () 70 | term_attrset (display.normal) 71 | term_refresh () 72 | end 73 | 74 | -- Tidy and close the terminal ready to exit. 75 | function term_finish () 76 | term_tidy () 77 | term_close () 78 | end 79 | 80 | -- Prints a line on the terminal. 81 | -- 82 | -- line - the line number within the buffer 83 | -- startcol - the horizontal scroll offset 84 | -- o - the starting offset of the line 85 | -- rp - the highlight rectangle, or nil if none 86 | -- 87 | -- If any part of the line is off the left-hand side of the screen, 88 | -- prints a `$' character in the left-hand column. If any part is off 89 | -- the right, prints a `$' character in the right-hand column. Any 90 | -- part that is within the highlight region is highlighted. If the 91 | -- final position is within the highlight region then the remainder of 92 | -- the line is also highlighted. 93 | local function draw_line (line, startcol, o, rp) 94 | term_move (line, 0) 95 | 96 | -- Draw body of line. 97 | local x = 0 98 | local line_len = buffer_line_len (buf, o) 99 | for i = startcol, math.huge do 100 | if i >= line_len or x >= win.ewidth then 101 | break 102 | end 103 | term_attrset ((rp and in_region (o, i, rp)) and display.reverse or display.normal) 104 | local c = get_buffer_char (buf, o + i) 105 | if posix.isprint (c) then 106 | term_addstr (c) 107 | x = x + 1 108 | else 109 | local s = make_string_printable (c, nil, x) 110 | term_addstr (s:sub (1, math.min (#s, win.fwidth - x))) 111 | x = x + #s 112 | end 113 | end 114 | 115 | term_addstr (string.rep (" ", win.fwidth - x)) 116 | term_attrset (display.normal) 117 | 118 | -- Draw end of line. 119 | if x >= win.fwidth then 120 | term_move (line, win.fwidth - 1) 121 | term_addstr ('$') 122 | end 123 | end 124 | 125 | local function calculate_highlight_region () 126 | if buf.mark == nil then 127 | return nil 128 | end 129 | return region_new (get_buffer_pt (buf), buf.mark.o) 130 | end 131 | 132 | local function draw_border () 133 | term_attrset (display.reverse) 134 | term_addstr (string.rep ('-', win.ewidth)) 135 | term_attrset (display.normal) 136 | end 137 | 138 | local function draw_status_line (line, wp) 139 | term_move (line, 0) 140 | draw_border() 141 | 142 | term_attrset (display.reverse) 143 | term_move (line, 0) 144 | local n = get_buffer_line (buf) 145 | 146 | local as = "--" 147 | 148 | -- Buffer state flags 149 | if buf.modified and buf.readonly then 150 | as = as .. "%*" 151 | elseif buf.modified then 152 | as = as .. "**" 153 | elseif buf.readonly then 154 | as = as .. "%%" 155 | else 156 | as = as .. "--" 157 | end 158 | 159 | -- File name 160 | as = as .. string.format (" %-15s ", buf.filename) 161 | 162 | -- Percentage of the way through the file 163 | as = as .. string.format ("%3d%%", ((get_buffer_pt (buf) - 1) * 100 // math.max (get_buffer_size (buf), 1))) 164 | 165 | -- Coordinates 166 | as = as .. string.format (" %-9s (", string.format ("(%d,%d)", n + 1, get_goalc ())) 167 | 168 | -- Mode flags 169 | local flags = {} 170 | if thisflag.defining_macro then 171 | table.insert (flags, "Def") 172 | end 173 | if buf.search then 174 | table.insert (flags, "Search") 175 | end 176 | as = as .. table.concat (flags, " ") .. ")" 177 | 178 | -- Display status line 179 | term_addstr (as:sub (1, term_width ())) 180 | term_attrset (display.normal) 181 | end 182 | 183 | local start_column = 0 -- start column of the window (>0 if scrolled sideways). 184 | local cursor_screen_column = 0 -- screen column of cursor 185 | 186 | local function draw_window (topline, wp) 187 | local rp = calculate_highlight_region () 188 | 189 | -- Find the first line to display on the first screen line. 190 | local o = buffer_start_of_line (buf, get_buffer_pt (buf)) 191 | local i = wp.topdelta 192 | while i > 0 and o > 1 do 193 | o = assert (buffer_prev_line (buf, o)) 194 | i = i - 1 195 | end 196 | 197 | -- Draw the window lines. 198 | for i = topline, wp.eheight + topline do 199 | -- Clear the line. 200 | term_move (i, 0) 201 | term_clrtoeol () 202 | 203 | -- If at the end of the buffer, don't write any text. 204 | if o ~= nil then 205 | draw_line (i, start_column, o, rp) 206 | 207 | if start_column > 0 then 208 | term_move (i, 0) 209 | term_addstr ('$') 210 | end 211 | 212 | o = buffer_next_line (buf, o) 213 | end 214 | end 215 | 216 | -- Draw the status line only if there is available space after the 217 | -- buffer text space. 218 | if wp.fheight > wp.eheight then 219 | draw_status_line (topline + wp.eheight, wp) 220 | end 221 | end 222 | 223 | 224 | -- Popup 225 | 226 | -- Contents of popup window. 227 | local popup_text 228 | local popup_line = 0 229 | 230 | -- Set the popup string to `s'. 231 | function popup_set (s) 232 | popup_text = s and AStr (s) 233 | popup_line = 0 234 | end 235 | 236 | -- Clear the popup string. 237 | function popup_clear () 238 | popup_set () 239 | end 240 | 241 | -- Scroll the popup text and loop having reached the bottom. 242 | function popup_scroll_down_and_loop () 243 | popup_line = popup_line + win.fheight - 3 244 | if popup_line > popup_text:lines () then 245 | popup_line = 0 246 | end 247 | term_display () 248 | end 249 | 250 | -- Scroll down the popup text. 251 | function popup_scroll_down () 252 | local h = win.fheight - 3 253 | popup_line = math.min (popup_line + h, popup_text:lines () + 1 - h) 254 | term_display () 255 | end 256 | 257 | -- Scroll up the popup text. 258 | function popup_scroll_up () 259 | popup_line = popup_line - math.min (win.fheight - 3, popup_line) 260 | term_display () 261 | end 262 | 263 | -- Draw the popup window. 264 | local function draw_popup () 265 | assert (popup_text) 266 | 267 | -- Number of lines of popup_text that will fit on the terminal. 268 | -- Allow 3 for the border above, and minibuffer and status line below. 269 | local h = win.fheight - 3 270 | -- Number of lines. 271 | local l = popup_text:lines () 272 | -- Position of top of popup == number of lines not to use. 273 | local y = math.max (h - l - 1, 0) 274 | 275 | term_move (y, 0) 276 | draw_border () 277 | 278 | -- Draw popup text, and blank lines to bottom of window. 279 | local o = 1 280 | for l = 0, popup_line - 1 do 281 | o = popup_text:next_line (o) 282 | end 283 | for i = 1, h - y + 1 do 284 | if o then 285 | term_addstr (tostring (popup_text:sub (o, popup_text:end_of_line (o)))) 286 | o = popup_text:next_line (o) 287 | end 288 | term_clrtoeol () 289 | end 290 | end 291 | 292 | -- Scans `s' and replaces each character with a string of one or 293 | -- more printable characters. The returned string is suitable for 294 | -- printing at screen column `col' (default 0); the screen column 295 | -- only matters if `s' contains tab characters. 296 | -- 297 | -- Scanning stops when the screen column reaches or exceeds `goal', 298 | -- or when `s' is exhausted. The number of input characters 299 | -- scanned is returned as a second return value. If no `goal' is 300 | -- passed, `math.huge' is assumed. 301 | -- 302 | -- Characters that are already printable expand to themselves. 303 | -- Characters from 0 to 26 are replaced with strings from `^@' to 304 | -- `^Z'. 305 | -- Tab characters are replaced with enough spaces (but always 306 | -- at least one) to reach a screen column that is a multiple of 307 | -- `tab_width'. 308 | -- Newline characters must not occur in `s'. 309 | -- Other characters are replaced with a backslash followed by 310 | -- their hex character code. 311 | function make_string_printable (s, goal, col) 312 | col = col or 0 313 | goal = goal or math.huge 314 | 315 | local ctrls = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ" 316 | local ret, pos = "", 0 317 | for i = 1, #s do 318 | local c = s[i] -- if s is a string c is a string, otherwise a byte 319 | if type (c) == "number" then c = string.char (c) end 320 | assert (c ~= '\n') 321 | 322 | local x = col + #ret 323 | if x >= goal then 324 | break 325 | end 326 | 327 | if c == '\t' then 328 | ret = ret .. string.rep (' ', tab_width - (x % tab_width)) 329 | elseif string.byte (c) < #ctrls then 330 | ret = ret .. '^' .. ctrls[string.byte (c) + 1] 331 | elseif posix.isprint (c) then 332 | ret = ret .. c 333 | -- FIXME: For double-width characters add a '\0' too so the length of 334 | -- 'ret' matches the display width. 335 | else 336 | ret = ret .. '\\' .. string.format ("%x", string.byte (c)) 337 | end 338 | 339 | pos = pos + 1 340 | end 341 | 342 | return ret 343 | end 344 | 345 | -- Calculate start_column and cursor_screen_column. 346 | -- 347 | -- `start_column' is always a multiple of a third of a screen width. It is 348 | -- chosen so as to put the cursor in the middle third, unless the cursor is near 349 | -- one or other end of the line, in which case it is chosen to show as much of 350 | -- the line as possible. 351 | local function calculate_start_column () 352 | local width = win.ewidth 353 | local third_width = math.max (1, math.floor (width / 3)) 354 | 355 | -- Calculate absolute columns of cursor and end of line. 356 | local x = get_goalc () 357 | local length = #make_string_printable (get_line ()) 358 | 359 | -- Choose start_column. 360 | if x < third_width or length < width then 361 | -- No-brainer cases: show left-hand end of line. 362 | start_column = 0 363 | else 364 | -- Put cursor in the middle third. 365 | start_column = x - (x % third_width) - third_width 366 | -- But scroll left if the right-hand end of the line stays on the screen. 367 | while start_column + width >= length + third_width do 368 | start_column = start_column - third_width 369 | end 370 | end 371 | 372 | -- Consequently, calculate screen-relative column. 373 | cursor_screen_column = x - start_column 374 | end 375 | 376 | function term_display () 377 | calculate_start_column () 378 | draw_window (0, win) 379 | if popup_text then 380 | draw_popup () 381 | end 382 | term_redraw_cursor () 383 | end 384 | 385 | function term_redraw_cursor () 386 | term_move (win.topdelta, cursor_screen_column) 387 | end 388 | -------------------------------------------------------------------------------- /zee/term_curses.lua: -------------------------------------------------------------------------------- 1 | -- Curses terminal 2 | -- 3 | -- Copyright (c) 2009-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | local codetokey, keytocode, key_buf 21 | 22 | local ESC = 0x1b 23 | local ESCDELAY = 500 24 | 25 | local resumed = true 26 | 27 | local function keypad (on) 28 | local capstr = curses.tigetstr (on and "smkx" or "rmkx") 29 | if capstr then 30 | io.stdout:write (capstr) 31 | io.stdout:flush () 32 | end 33 | end 34 | 35 | function term_init () 36 | curses.initscr () 37 | 38 | display = { 39 | normal = curses.A_NORMAL, 40 | standout = curses.A_STANDOUT, 41 | underline = curses.A_UNDERLINE, 42 | reverse = curses.A_REVERSE, 43 | blink = curses.A_BLINK, 44 | dim = curses.A_DIM, 45 | bold = curses.A_BOLD, 46 | protect = curses.A_PROTECT, 47 | invisible = curses.A_INVIS, 48 | 49 | black = curses.COLOR_BLACK, 50 | red = curses.COLOR_RED, 51 | green = curses.COLOR_GREEN, 52 | yellow = curses.COLOR_YELLOW, 53 | blue = curses.COLOR_BLUE, 54 | magenta = curses.COLOR_MAGENTA, 55 | cyan = curses.COLOR_CYAN, 56 | white = curses.COLOR_WHITE, 57 | } 58 | 59 | key_buf = list {} 60 | 61 | -- from curses key presses to editor keycodes 62 | codetokey = tree {} 63 | 64 | -- from editor keycodes back to curses key presses 65 | keytocode = {} 66 | 67 | -- Starting with specially named keys: 68 | for code, key in pairs { 69 | [0x9] = "Tab", 70 | [0xd] = "Return", 71 | [0x20] = "Space", 72 | [0x7f] = "Ctrl-?", 73 | ["kbs"] = "Backspace", 74 | ["kdch1"] = "Delete", 75 | ["kDC5"] = "Ctrl-Delete", 76 | ["kcud1"] = "Down", 77 | ["kend"] = "End", 78 | ["kEND5"] = "Ctrl-End", 79 | ["kf1"] = "F1", 80 | ["kf2"] = "F2", 81 | ["kf3"] = "F3", 82 | ["kf4"] = "F4", 83 | ["kf5"] = "F5", 84 | ["kf6"] = "F6", 85 | ["kf7"] = "F7", 86 | ["kf8"] = "F8", 87 | ["kf9"] = "F9", 88 | ["kf10"] = "F10", 89 | ["kf11"] = "F11", 90 | ["kf12"] = "F12", 91 | ["khome"] = "Home", 92 | ["kHOM5"] = "Ctrl-Home", 93 | ["kich1"] = "Insert", 94 | ["kcub1"] = "Left", 95 | ["kLFT5"] = "Ctrl-Left", 96 | ["knp"] = "PageDown", 97 | ["kpp"] = "PageUp", 98 | ["kcuf1"] = "Right", 99 | ["kRIT5"] = "Ctrl-Right", 100 | ["kspd"] = "Ctrl-z", 101 | ["kcuu1"] = "Up" 102 | } do 103 | local codes = nil 104 | if type (code) == "string" then 105 | local s = curses.tigetstr (code) 106 | if s then 107 | codes = {} 108 | for i = 1, #s do 109 | table.insert (codes, s:byte (i)) 110 | end 111 | end 112 | else 113 | codes = {code} 114 | end 115 | 116 | if codes then 117 | key = keycode (key) 118 | keytocode[key] = codes 119 | codetokey[codes] = key 120 | end 121 | end 122 | 123 | -- Reverse lookup of a lone ESC. 124 | keytocode[keycode "Escape"] = {ESC} 125 | 126 | -- ...fallback to 0x7f for backspace if terminfo doesn't know better 127 | if not curses.tigetstr ("kbs") then 128 | keytocode[keycode "Backspace"] = {0x7f} 129 | end 130 | if not codetokey[{0x7f}] then 131 | codetokey[{0x7f}] = keycode "Backspace" 132 | end 133 | 134 | -- ...inject remaining ASCII key codes 135 | for code = 0, 0x7f do 136 | local key = nil 137 | if not codetokey[{code}] then 138 | -- control keys 139 | if code < 0x20 then 140 | key = keycode ("Ctrl-" .. string.char (code + 0x40):lower ()) 141 | 142 | -- printable keys 143 | elseif code < 0x80 then 144 | key = keycode (string.char (code)) 145 | 146 | -- meta keys 147 | else 148 | local basekey = codetokey[{code - 0x80}] 149 | if type (basekey) == "table" and basekey.key then 150 | key = "Alt-" + basekey 151 | end 152 | end 153 | 154 | if key ~= nil then 155 | codetokey[{code}] = key 156 | keytocode[key] = {code} 157 | end 158 | end 159 | end 160 | 161 | curses.echo (false) 162 | curses.nl (false) 163 | curses.raw (true) 164 | curses.stdscr ():meta (true) 165 | curses.stdscr ():intrflush (false) 166 | curses.stdscr ():keypad (false) 167 | 168 | posix.signal (posix.SIGCONT, function () resumed = true end) 169 | end 170 | 171 | function term_close () 172 | -- Revert terminal to cursor mode before exiting. 173 | keypad (false) 174 | 175 | curses.endwin () 176 | end 177 | 178 | function term_getkey_unfiltered (delay) 179 | if #key_buf > 0 then 180 | return table.remove (key_buf) 181 | end 182 | 183 | -- Put terminal in application mode if necessary. 184 | if resumed then 185 | keypad (true) 186 | resumed = nil 187 | end 188 | 189 | curses.stdscr ():timeout (delay) 190 | 191 | local c 192 | repeat 193 | c = curses.stdscr ():getch () 194 | if curses.KEY_RESIZE == c then 195 | resize_window () 196 | execute_command ("move-redraw") 197 | end 198 | until curses.KEY_RESIZE ~= c 199 | 200 | return c 201 | end 202 | 203 | local function unget_codes (codes) 204 | key_buf = list.concat (key_buf, std.ireverse (codes)) 205 | end 206 | 207 | function term_getkey (delay) 208 | local codes, key = {} 209 | 210 | local c = term_getkey_unfiltered (delay) 211 | if c == ESC then 212 | -- Detecting ESC is tricky... 213 | c = term_getkey_unfiltered (ESCDELAY) 214 | if c == nil then 215 | -- ...if nothing follows quickly enough, assume ESC keypress... 216 | key = keycode "Escape" 217 | else 218 | -- ...see whether the following chars match an escape sequence... 219 | codes = { ESC } 220 | while true do 221 | table.insert (codes, c) 222 | key = codetokey[codes] 223 | if key and key.key then 224 | -- ...return the codes for the matched escape sequence. 225 | break 226 | elseif key == nil then 227 | -- ...no match, rebuffer unmatched chars and return Escape. 228 | unget_codes (list.tail (list (codes))) 229 | key = keycode "Escape" 230 | break 231 | end 232 | -- ...partial match, fetch another char and try again. 233 | c = term_getkey_unfiltered (GETKEY_DEFAULT) 234 | end 235 | end 236 | else 237 | -- Detecting non-Escape involves fetching chars and matching... 238 | while true do 239 | if c ~= nil then 240 | table.insert (codes, c) 241 | end 242 | key = codetokey[codes] 243 | if c == nil or (key and key.key) then 244 | -- ...code lookup matched a key, return it. 245 | break 246 | elseif key == nil then 247 | -- ...or return nil for an invalid lookup code. 248 | key = nil 249 | break 250 | end 251 | -- ...for a partial match, fetch another char and try again. 252 | c = term_getkey_unfiltered (GETKEY_DEFAULT) 253 | end 254 | end 255 | 256 | if key == keycode "Escape" then 257 | local another = term_getkey (GETKEY_DEFAULT) 258 | if another then key = "Alt-" + another end 259 | end 260 | 261 | if c == nil then 262 | return nil 263 | end 264 | return key 265 | end 266 | 267 | 268 | -- If key can be represented as an ASCII byte, return it, otherwise 269 | -- return nil. 270 | function term_keytobyte (key) 271 | local codes = keytocode[key] 272 | if codes and #codes == 1 and 0xff >= codes[1] then 273 | return codes[1] 274 | end 275 | return nil 276 | end 277 | 278 | function term_ungetkey (key) 279 | local codevec = list {} 280 | 281 | if key ~= nil then 282 | if key.ALT then 283 | codevec = list { ESC } 284 | key = key - "Alt-" 285 | end 286 | 287 | local code = keytocode[key] 288 | if code then 289 | codevec = list.concat (codevec, code) 290 | end 291 | end 292 | 293 | unget_codes (codevec) 294 | end 295 | 296 | function term_buf_len () 297 | return #key_buf 298 | end 299 | 300 | function term_move (y, x) 301 | curses.stdscr ():move (y, x) 302 | end 303 | 304 | function term_clrtoeol () 305 | curses.stdscr ():clrtoeol () 306 | end 307 | 308 | function term_refresh () 309 | curses.stdscr ():refresh () 310 | end 311 | 312 | function term_clear () 313 | curses.stdscr ():clear () 314 | end 315 | 316 | function term_addstr (s) 317 | curses.stdscr ():addstr (s) 318 | end 319 | 320 | function term_attrset (attrs) 321 | curses.stdscr ():attrset (attrs or 0) 322 | end 323 | 324 | function term_beep () 325 | curses.beep () 326 | end 327 | 328 | function term_width () 329 | return curses.cols () 330 | end 331 | 332 | function term_height () 333 | return curses.lines () 334 | end 335 | -------------------------------------------------------------------------------- /zee/undo.lua: -------------------------------------------------------------------------------- 1 | -- Undo facility functions 2 | -- 3 | -- Copyright (c) 2010-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | -- Save a reverse delta for doing undo. 21 | local function undo_save (ty, o, osize, size) 22 | local u = {type = ty, next = buf.last_undo, o = o} 23 | 24 | if ty == "replace block" then 25 | u.size = size 26 | u.text = get_buffer_region (buf, region_new (o, o + osize)) 27 | u.unchanged = not buf.modified 28 | end 29 | 30 | buf.last_undo = u 31 | end 32 | 33 | 34 | function undo_start_sequence () 35 | undo_save ("start sequence", get_buffer_pt (buf)) 36 | end 37 | 38 | function undo_end_sequence () 39 | undo_save ("end sequence") 40 | end 41 | 42 | function undo_save_block (o, osize, size) 43 | undo_save ("replace block", o, osize, size) 44 | end 45 | 46 | -- Set unchanged flags to false. 47 | function undo_set_unchanged (u) 48 | while u do 49 | u.unchanged = false 50 | u = u.next 51 | end 52 | end 53 | 54 | -- Revert an action. 55 | -- Return the next undo entry. 56 | local function revert_action (up) 57 | if up.type == "end sequence" then 58 | undo_start_sequence () 59 | up = up.next 60 | while up.type ~= "start sequence" do 61 | up = revert_action (up) 62 | end 63 | undo_end_sequence () 64 | end 65 | 66 | goto_offset (up.o) 67 | if up.type == "replace block" then 68 | replace_string (up.size, up.text) 69 | goto_offset (up.o) 70 | if up.unchanged then 71 | buf.modified = false 72 | end 73 | end 74 | 75 | return up.next 76 | end 77 | 78 | Define ("edit-undo", 79 | [[ 80 | Undo some previous changes. 81 | Repeat this command to undo more changes. 82 | ]], 83 | function () 84 | if not buf.next_undo then 85 | minibuf_error ("No further undo information") 86 | buf.next_undop = buf.last_undo 87 | return true 88 | end 89 | 90 | buf.next_undo = revert_action (buf.next_undo) 91 | minibuf_write ("Undo!") 92 | end 93 | ) 94 | 95 | Define ("edit-revert", 96 | [[ 97 | Undo until buffer is unmodified. 98 | ]], 99 | function () 100 | while buf.modified do 101 | execute_command ("edit-undo") 102 | end 103 | end 104 | ) 105 | -------------------------------------------------------------------------------- /zee/variables.lua: -------------------------------------------------------------------------------- 1 | -- Editor variables 2 | -- 3 | -- Copyright (c) 2010-2012 Free Software Foundation, Inc. 4 | -- 5 | -- This file is part of Zee. 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify it 8 | -- under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3, or (at your option) 10 | -- any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program. If not, see . 19 | 20 | Define ("indent-width", "Number of spaces inserted for an indentation.", 21 | 2) 22 | Define ("caseless-search", "Whether searching ignores case by default.", 23 | true) 24 | Define ("case-replace", "Whether `query-replace' should preserve case.", 25 | false) 26 | 27 | 28 | function get_variable (var) 29 | return (env[var] or {}).val 30 | end 31 | 32 | function preferences_set_variable (var, val) 33 | env[var] = env[var] or {} 34 | env[var].val = val 35 | end 36 | 37 | Define ("preferences-set-variable", 38 | [[ 39 | Set a variable to the specified value. 40 | ]], 41 | function (var, val) 42 | var = var or (interactive () and 43 | minibuf_read_completion ("Set variable: ", 44 | completion_new (filter (function (e) 45 | return not command_exists (e) 46 | end, 47 | std.ielems, table.keys (env))), 48 | "variable")) 49 | if var == "" then 50 | return true 51 | end 52 | 53 | if val == nil and interactive () then 54 | val = minibuf_read (string.format ("Set %s to value: ", var)) 55 | end 56 | if val == nil then 57 | return ding () 58 | end 59 | preferences_set_variable (var, val) 60 | end 61 | ) 62 | -------------------------------------------------------------------------------- /zee/zee.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | A=--[[ exec @LUA@ "$0" "$@" # -*- mode: lua; -*- ]]A 3 | -- 4 | -- Program initialisation 5 | -- 6 | -- Copyright (c) 2010-2014 Free Software Foundation, Inc. 7 | -- 8 | -- This file is part of Zee. 9 | -- 10 | -- This program is free software; you can redistribute it and/or modify it 11 | -- under the terms of the GNU General Public License as published by 12 | -- the Free Software Foundation; either version 3, or (at your option) 13 | -- any later version. 14 | -- 15 | -- This program is distributed in the hope that it will be useful, but 16 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 17 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | -- General Public License for more details. 19 | -- 20 | -- You should have received a copy of the GNU General Public License 21 | -- along with this program. If not, see . 22 | 23 | 24 | -- Constants set by configure 25 | PACKAGE = "@PACKAGE@" 26 | PACKAGE_NAME = "@PACKAGE_NAME@" 27 | PACKAGE_BUGREPORT = "@PACKAGE_BUGREPORT@" 28 | VERSION = "@VERSION@" 29 | 30 | require "luarocks.loader" 31 | require (PACKAGE) 32 | 33 | 34 | local function err (err) 35 | term_close () 36 | print ("Internal error. Please report this bug with steps to reproduce the problem.") 37 | print (debug.traceback(err, 2)) 38 | os.exit (2) 39 | end 40 | 41 | xpcall (main, err) 42 | --------------------------------------------------------------------------------