├── .gitignore ├── GNUmakefile ├── LICENSE.txt ├── README.md ├── TODO.md ├── benchmarks ├── buffer.scm ├── editor.scm ├── run.scm └── util.scm ├── bin └── edward.scm ├── doc ├── .gitignore ├── GNUmakefile ├── README.md ├── index.md └── page.theme ├── edward.egg ├── edward.release-info ├── lib ├── buffer.sld ├── buffer │ ├── buffer.scm │ ├── srfi214-minimal.scm │ └── stack.scm ├── cli.scm ├── cli.sld ├── ed │ ├── addr.scm │ ├── addr.sld │ ├── cmd.scm │ ├── cmd.sld │ ├── editor.scm │ ├── editor.sld │ ├── posix.scm │ └── posix.sld ├── parse.sld ├── parse │ ├── parse.scm │ ├── repl.scm │ └── util.scm ├── replace.scm ├── replace.sld ├── util.scm └── util.sld └── tests ├── buffer.scm ├── integration ├── address-chain-eval-order │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── address-chain-fully-eval │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── address-range-large-address │ └── cmds ├── address-range-semicolon-list │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── address-range-semicolon-number │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── address-range-semicolon-print │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── address-ranges │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── address-regex-syntax-error │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── append-and-list │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── append-and-n │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── append-and-print │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── append-at-beginning │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── append-at-end │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── append-between │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── append-empty-not-modified │ └── cmds ├── append-line-update │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── append-newlines │ └── cmds ├── append-nth │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── change-and-n │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── change-default │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── change-delete-everything │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── change-insert-more-lines │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── change-line-update │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── change-no-input │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── command-mode-eof-modified │ └── cmds ├── command-mode-eof │ └── cmds ├── confirm-quit-when-no-tty │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── copy-to-end │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── copy-to-start │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── copy-with-offset │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── delete-and-append │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── delete-entire-buffer │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── delete-last-line │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── delete-partial │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── delete-single-addr │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── discard-first-addr │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── edit-confirm │ ├── cmds │ ├── opts │ └── testdata │ │ ├── first │ │ └── second ├── edit-custom-file │ ├── cmds │ ├── opts │ └── testdata │ │ ├── first │ │ └── second ├── edit-default │ ├── cmds │ └── testdata │ │ └── input-file ├── edit-marks-discarded │ ├── cmds │ ├── opts │ └── testdata │ │ ├── first │ │ └── second ├── edit-twice │ ├── cmds │ └── testdata │ │ ├── first │ │ └── second ├── edit-unset-modified │ ├── cmds │ ├── opts │ └── testdata │ │ ├── first │ │ └── second ├── edit-with-command │ └── cmds ├── filename-line-unchanged │ ├── cmds │ ├── opts │ └── testdata │ │ ├── first │ │ └── second ├── filename-new-file │ ├── cmds │ ├── opts │ └── testdata │ │ ├── first │ │ └── second ├── filename-same-file │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── filename-shell-command │ └── cmds ├── filename-silent │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── forward-backward-current-matches │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-append-omit-terminator │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-append │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-change │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-delete-everything │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-delim │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-delimiter-omitted-substitute │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-empty │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-esc-delim │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-insert │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-multiline │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-multiple-commands │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-no-match │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-no-terminating-dot │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-non-matched │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-null-re │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-print │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-regex-syntax-error │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-substitute-nomatch1 │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── global-substitute-nomatch2 │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── input-mode-eof │ └── cmds ├── insert-before │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── insert-zero │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── interactive-nested-global │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── interactive-no-previous │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── interactive-null-command │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── interactive-null-repeat │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── interactive-previous │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── interactive-repeat │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── interactive-unmatched │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── interactive │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── invalid-range │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── join-all │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── join-lines │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── join-nothing │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── line-number-default │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── line-number-empty │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── line-number-zero │ └── cmds ├── list-backslash │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── list-multiple-lines │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── list-pad-with-zeros │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── list-unicode │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── mark-and-delete │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── mark-and-move │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── mark-empty-buffer │ └── cmds ├── mark-first-line │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── mark-invalid │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── mark-overwrite │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── mark-zero-line │ └── cmds ├── move-after │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── move-between │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── move-overlapping-range │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── move-to-end │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── move-to-start │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── move-update-current-on-single-line │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── multiple-addresses │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── no-null-re │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── nonexistend-file-read │ └── cmds ├── nonexistend-file-write │ └── cmds ├── null-command-with-address │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── null-command-with-zero-address │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── null-command │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── null-re-range │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── null-re │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── number-change-line │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── number-default │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── number-full │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── number-partial │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── omitting-re-delimiter │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── pass-shell-command-as-cmdarg │ ├── cmds │ └── opts ├── prefix-print-with-print │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── print-match-backward-multiple-matches │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── print-match-backward │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── print-match-forward-no-match │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── print-match-forward-wraparound │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── print-match-forward │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── print-single │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── print │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── quit-address │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── quit-confirmed │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── quit-file-modified │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── quit-no-file │ ├── cmds │ └── opts ├── quit-not-modified │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── quit-without-checking │ └── cmds ├── read-command-empty │ └── cmds ├── read-command-twice │ └── cmds ├── read-dont-remember-command │ └── cmds ├── read-from-command │ └── cmds ├── read-no-space │ ├── cmds │ └── testdata │ │ └── in ├── read-set-default │ ├── cmds │ └── testdata │ │ └── input-file ├── read-twice │ ├── cmds │ └── testdata │ │ └── in ├── read-write-no-file │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── regex-empty-file │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── run.sh ├── shell-escape-filename │ └── cmds ├── shell-filename-multiple │ ├── cmds │ ├── opts │ └── testdata │ │ ├── first-file │ │ └── second-file ├── shell-filename │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── shell-no-filename │ └── cmds ├── shell-no-previous │ └── cmds ├── shell-previous-append │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── shell-previous-with-filename │ └── cmds ├── shell-previous │ └── cmds ├── silent-mode │ ├── cmds │ ├── opts │ └── testdata │ │ ├── first-file │ │ └── second-file ├── special-addresses │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-and-number │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-and-print │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-append │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-backreference │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-change-line │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-delimiter-escaped │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-delimiter │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-differ-matched-twice │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-empty-replace │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-empty-submatch │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-first │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-global │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-insert-multiple-newlines │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-invalid-backref │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-mark-touched │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-mark-untouched │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-matched-twice │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-missing-pattern │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-modified-but-same │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-multiline-print │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-multiline │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-no-match │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-no-prev-replace │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-non-participating-submatch │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-null-re │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-percent-delim │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-prev-replace-empty │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-prev-replace │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── substitute-regex-syntax-error │ └── cmds ├── substitute-simple │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── terminate-after-first-error │ └── cmds ├── undo-append │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── undo-change │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── undo-copy │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── undo-delete │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── undo-edit-command │ ├── cmds │ ├── opts │ └── testdata │ │ ├── first │ │ └── second ├── undo-global-non-matched │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── undo-global │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── undo-insert │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── undo-join │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── undo-move │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── undo-nothing │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── undo-read │ ├── cmds │ ├── opts │ └── testdata │ │ ├── input-file │ │ └── to-be-read ├── undo-redo │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── undo-substitute │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── undo-undo │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── write-default-empty │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── write-default │ ├── cmds │ ├── opts │ └── testdata │ │ └── input-file ├── write-empty-to-command │ └── cmds ├── write-no-file │ └── cmds ├── write-partial │ ├── cmds │ ├── opts │ ├── out │ └── testdata │ │ └── input-file ├── write-to-command-modified │ ├── cmds │ └── testdata │ │ └── input-file ├── write-to-command │ ├── cmds │ └── testdata │ │ └── input-file ├── write-update-filename-cmd │ ├── cmds │ └── testdata │ │ └── file ├── write-update-filename │ ├── cmds │ └── testdata │ │ └── file └── zero-address │ ├── cmds │ ├── opts │ └── testdata │ └── input-file ├── interactive ├── README.md ├── eof-confirm-with-quit │ ├── cmds │ └── expected ├── eof-modified-reset │ ├── cmds │ └── expected ├── eof-modified │ ├── cmds │ └── expected ├── eof │ ├── cmds │ └── expected ├── input-mode-eof-partial-multiple │ ├── cmds │ └── expected ├── input-mode-eof-partial │ ├── cmds │ └── expected ├── input-mode-eof │ ├── cmds │ └── expected ├── interactive-global-eof │ ├── cmds │ └── expected ├── interactive-unmatched-eof │ ├── cmds │ └── expected ├── prompt │ ├── cmds │ └── expected ├── quit-confirm-with-eof │ ├── cmds │ └── expected └── run.sh ├── parse-addr.scm ├── parse-cmd.scm ├── replace.scm ├── run.scm └── util.scm /.gitignore: -------------------------------------------------------------------------------- 1 | bin/edward 2 | output/ 3 | vendor/ 4 | edward*.build.sh 5 | edward*.import.scm 6 | edward*.import.so 7 | edward*.install.sh 8 | edward*.link 9 | edward*.so 10 | edward*.static.o 11 | edward*.c 12 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | # This Makefile is a wrapper around chicken-install(1) which eases building 2 | # edward without superuser rights and without requiring any configuration 3 | # of chicken-install. Furthermore, it supports optional dependency vendoring 4 | # to build edward without network access. 5 | # 6 | # By default, the Makefile builds a statically linked binary. For development 7 | # purposes it can be desirable to do dynamic linked builds instead. To do so 8 | # the PACKAGE environment variable can be set to zero. 9 | PREFIX ?= /usr/local 10 | BINDIR ?= $(PREFIX)/bin 11 | DOCDIR ?= $(PREFIX)/share/doc/edward 12 | 13 | # By default, build a statically linked version for packaging. 14 | # If package is zero, build a dynamically linked version instead. 15 | PACKAGE ?= 1 16 | ifneq ($(PACKAGE),0) 17 | INSTALL_FLAGS = -feature package 18 | endif 19 | 20 | # Install all CHICKEN files relative to ./output 21 | # 22 | # See: https://bugs.call-cc.org/ticket/1792 23 | 24 | # Respect CHICKEN_REPOSITORY_PATH if set in the environment 25 | CHICKEN_REPOSITORY_PATH ?= $(shell env -i chicken-install -repository) 26 | 27 | export CHICKEN_INSTALL_PREFIX := $(CURDIR)/output 28 | export CHICKEN_INSTALL_REPOSITORY := $(CURDIR)/output 29 | export CHICKEN_REPOSITORY_PATH := $(CURDIR)/output:$(CHICKEN_REPOSITORY_PATH) 30 | 31 | # Optional dependency vendoring to build without network access 32 | # 33 | # Release tarballs include vendored dependencies (see make dist). 34 | 35 | VENDOR_DIRECTORY = $(CURDIR)/vendor 36 | ifneq ($(wildcard $(VENDOR_DIRECTORY)/*),) 37 | VENDORED=1 38 | endif 39 | 40 | all: 41 | ifdef VENDORED 42 | chicken-install -location $(VENDOR_DIRECTORY) $(shell ls $(VENDOR_DIRECTORY)) 43 | endif 44 | chicken-install $(INSTALL_FLAGS) 45 | 46 | check: export EDWARD=$(CHICKEN_INSTALL_PREFIX)/bin/edward 47 | check: 48 | chicken-install -test 49 | @./tests/integration/run.sh 50 | @./tests/interactive/run.sh 51 | 52 | bench: 53 | csi -quiet -script benchmarks/run.scm 54 | 55 | install: 56 | install -Dm755 $(CHICKEN_INSTALL_PREFIX)/bin/edward "$(DESTDIR)$(BINDIR)/edward" 57 | install -Dm644 README.md "$(DESTDIR)$(DOCDIR)/README.md" 58 | 59 | vendor: 60 | env -i CHICKEN_EGG_CACHE=$(VENDOR_DIRECTORY) chicken-install -r -recursive -test 61 | find $(VENDOR_DIRECTORY) \( -name STATUS -a -type f \) -exec rm {} + 62 | # XXX: Make sure to remove the vendor directory before running `make dist`. 63 | # As libraries are, unfortunately, build within the vendor directory. 64 | dist: VERSION = $(shell git describe --tags) 65 | dist: vendor 66 | mkdir -p edward-$(VERSION) 67 | cp -R LICENSE.txt GNUmakefile README.md bin edward.egg lib tests vendor edward-$(VERSION) 68 | tar -czf edward-$(VERSION).tar.gz edward-$(VERSION) 69 | rm -rf edward-$(VERSION) 70 | 71 | .PHONY: all check bench install vendor dist 72 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Library Interface 2 | 3 | * Introduce namespaces for command names 4 | * By making command names a list, e.g. `'(posix quit)` 5 | * POSIX namespace should be treated as reserved 6 | * Documentation: Clarify interaction between `edward ed addr` and `edward ed editor` 7 | * `(edward ed cli)`: Allow defining custom command-line options 8 | * Provide dedicated types for addresses and ranges 9 | * Add `(chicken type)` annotations for the public API to catch more 10 | usage errors during compile-time instead of run-time. 11 | * Provide an `(edward)` meta-library which imports all sub-libraries. 12 | 13 | # Miscellaneous 14 | 15 | * Consider using Declarations and (chicken type) to enable more optimizations 16 | * https://wiki.call-cc.org/programming-for-performance 17 | * https://wiki.call-cc.org/man/5/Declarations 18 | * https://wiki.call-cc.org/man/5/Foreign%20type%20specifiers 19 | * In append/insert/… command: Verify that the address is valid before 20 | entering insert mode. For example, when performing `2a` on an empty 21 | file the append will only error out after all text has been entered. 22 | * Figure out why edward is slower when compiled statically with eggs (linkage static) 23 | * Profile larger ed inputs (e.g. as generated by a fuzzer) with 24 | chicken-profile and figure identify (parsing) procedures which 25 | could be further optimized for performance 26 | * Improve parser error messages (mostly returns `failed char pred` currently) 27 | * Consider prefixing parser errors with command parser name 28 | (how should the `g` command be handled in this regard?) 29 | * Consider adding column information to parser errors 30 | * Add parse-with-failure-reason to more parser combinators 31 | * Refactor parse-line in a way that it can consume end-of-file. 32 | Requires refactoring of parse-input-mode. 33 | * Allow input with spaces in interactive tests 34 | * Probably requires rewriting the test runner in Python or something 35 | * Would enable adding tests for edge cases like c0fe7d15700cc1ca03198c05d3762f7516f185fe 36 | -------------------------------------------------------------------------------- /benchmarks/buffer.scm: -------------------------------------------------------------------------------- 1 | (import (edward buffer) 2 | (edward util)) 3 | 4 | (define-bench (buffer-append-single-at-end) 5 | (let ((buffer (make-buffer))) 6 | (repeat 7 | 10000 8 | (lambda () 9 | (buffer-append! 10 | buffer 11 | (buffer-length buffer) 12 | (list (random-string))))))) 13 | 14 | (define-bench (buffer-append-multi-at-end) 15 | (let ((buffer (make-buffer))) 16 | (repeat 17 | 10000 18 | (let ((next-size 1) 19 | (max-size 10)) 20 | (lambda () 21 | (buffer-append! 22 | buffer 23 | (buffer-length buffer) 24 | (generate-list random-string next-size)) 25 | (set! next-size (modulo (inc next-size) max-size))))))) 26 | 27 | (define-bench (buffer-append-single-randomly) 28 | (let ((buffer (make-buffer))) 29 | (repeat 30 | 10000 31 | (lambda () 32 | (buffer-append! 33 | buffer 34 | (pseudo-random-integer (buffer-length buffer)) 35 | (list (random-string))))))) 36 | 37 | (define-bench (buffer-remove-from-front) 38 | (let ((buffer (make-buffer)) 39 | (elems 15000)) 40 | (buffer-append! buffer 0 (generate-list random-string elems)) 41 | (repeat elems 42 | (lambda () 43 | (buffer-remove! buffer 1 1))))) 44 | 45 | (define-bench (buffer-remove-from-back) 46 | (let ((buffer (make-buffer)) 47 | (elems 15000)) 48 | (buffer-append! buffer 0 (generate-list random-string elems)) 49 | (repeat elems 50 | (lambda () 51 | (let ((len (buffer-length buffer))) 52 | (buffer-remove! buffer len len)))))) 53 | 54 | (define-bench (buffer-remove-entire-content) 55 | (let ((buffer (make-buffer)) 56 | (elems 100000)) 57 | (buffer-append! buffer 0 (generate-list random-string elems)) 58 | (buffer-remove! buffer 1 elems))) 59 | 60 | (define-bench (buffer-join-entire-content) 61 | (let ((buffer (make-buffer)) 62 | (elems 30000)) 63 | (buffer-append! buffer 0 (generate-list random-string elems)) 64 | (buffer-join! buffer 1 elems))) 65 | -------------------------------------------------------------------------------- /benchmarks/editor.scm: -------------------------------------------------------------------------------- 1 | (import (edward ed editor) 2 | (edward ed addr)) 3 | 4 | (define-bench (editor-regex-match-line) 5 | (let ((e (make-text-editor #f "" "" #f)) 6 | (n 100000)) 7 | (editor-append! e 0 (generate-list random-string n)) 8 | (editor-append! e n '("bla bla 23foobar42 foo bar")) 9 | 10 | (range->lpair e 11 | (make-range (make-addr '(regex-forward . "[0-9][0-9]*foobar[0-9][0-9]* foo")))))) 12 | 13 | (define-bench (editor-get-lines-partial) 14 | (let ((e (make-text-editor #f "" "" #f)) 15 | (n 100000)) 16 | (editor-append! e 0 (generate-list random-string n)) 17 | (editor-get-lines e (cons 0 (/ n 2))))) 18 | 19 | (define-bench (editor-get-line-number-last) 20 | (let ((e (make-text-editor #f "" "" #f)) 21 | (n 100000)) 22 | (editor-append! e 0 (generate-list random-string n)) 23 | (let ((p (editor-get-lines e (cons n n)))) 24 | (editor-get-lnum e (car p))))) 25 | -------------------------------------------------------------------------------- /benchmarks/run.scm: -------------------------------------------------------------------------------- 1 | (import r7rs) 2 | 3 | ;; Amount of execution per benchmark. 4 | (define BENCHMARK_ITERATIONS 3) 5 | 6 | (include-relative "util.scm") 7 | (include-relative "buffer.scm") 8 | (include-relative "editor.scm") 9 | -------------------------------------------------------------------------------- /benchmarks/util.scm: -------------------------------------------------------------------------------- 1 | (import (edward util) 2 | (chicken random) 3 | (micro-benchmark)) 4 | 5 | (define (repeat n thunk) 6 | (when (> n 0) 7 | (thunk) 8 | (repeat (dec n) thunk))) 9 | 10 | (define (random-string . rest) 11 | (let ((siz (if (null? rest) 100 (car rest)))) 12 | (list->string 13 | (generate-list 14 | (lambda () 15 | (let ((ascii (+ (pseudo-random-integer 126) 33))) 16 | (integer->char ascii))) 17 | siz)))) 18 | 19 | (define (generate-list thunk size) 20 | (map 21 | (lambda (proc) 22 | (proc)) 23 | (make-list size thunk))) 24 | 25 | (define (time-stat sym stats) 26 | (define (msec->sec msec) 27 | (/ msec 1000000)) 28 | 29 | (define (round-off z n) 30 | (let ((power (expt 10 n))) 31 | (/ (round (* power z)) power))) 32 | 33 | (let ((el (assq sym stats))) 34 | (if (not el) 35 | (error (string-append "no element named '" (symbol->string sym) "' in statistics")) 36 | (round-off (msec->sec (cdr el)) 3)))) 37 | 38 | (define (run-benchmark name proc) 39 | (let* ((stats (benchmark-run (BENCHMARK_ITERATIONS) (proc)))) 40 | (display name) 41 | (display ":\t") 42 | (display (time-stat 'arithmetic-mean stats)) 43 | (display "s") 44 | (display " +/- ") 45 | (display (time-stat 'standard-deviation stats)) 46 | (display "s") 47 | (newline))) 48 | 49 | (define-syntax define-bench 50 | (syntax-rules () 51 | ((define-bench (NAME) BODY ...) 52 | (run-benchmark 53 | (symbol->string (quote NAME)) 54 | (lambda () 55 | BODY ...))))) 56 | -------------------------------------------------------------------------------- /bin/edward.scm: -------------------------------------------------------------------------------- 1 | (import (scheme base) 2 | (edward cli)) 3 | 4 | (cond-expand 5 | ((or chicken-script compiling) 6 | (edward-main)) 7 | (else #t)) 8 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | style.css 3 | -------------------------------------------------------------------------------- /doc/GNUmakefile: -------------------------------------------------------------------------------- 1 | # Can be set to an URL for any classless CSS framework. 2 | STYLESHEET ?= https://cdn.jsdelivr.net/gh/kognise/water.css@latest/dist/dark.css 3 | 4 | DISCOUNT = discount-theme 5 | DISCOUNT_FLAGS = -c +header,+idanchor 6 | 7 | SCMDOC = scmdoc 8 | SCMDOC_FLAGS = -s style.css 9 | 10 | SCMDOC_FILES = edward.ed.editor.html \ 11 | edward.ed.cmd.html \ 12 | edward.ed.addr.html \ 13 | edward.ed.posix.html \ 14 | edward.cli.html \ 15 | edward.util.html \ 16 | edward.parse.html \ 17 | edward.replace.html \ 18 | edward.buffer.html 19 | 20 | all: index.html style.css $(SCMDOC_FILES) 21 | clean: 22 | $(RM) index.html style.css $(SCMDOC_FILES) 23 | style.css: 24 | curl -sLo style.css $(STYLESHEET) 25 | index.html: index.md page.theme 26 | $(DISCOUNT) $(DISCOUNT_FLAGS) -o $@ $< 27 | 28 | edward.%.html: %.sld 29 | $(SCMDOC) $(SCMDOC_FLAGS) $< 30 | edward.ed.%.html: ed/%.sld 31 | $(SCMDOC) $(SCMDOC_FLAGS) $< 32 | 33 | # XXX: This essentially duplicates the dependency tracking of edward.egg. 34 | edward.ed.editor.html: ed/editor.sld ed/editor.scm 35 | edward.ed.cmd.html: ed/cmd.sld ed/cmd.scm 36 | edward.ed.addr.html: ed/addr.sld ed/addr.scm 37 | edward.ed.posix.html: ed/posix.sld ed/posix.scm 38 | edward.cli.html: cli.sld cli.scm 39 | edward.util.html: util.sld util.scm 40 | edward.replace.html: replace.sld replace.scm 41 | edward.parse.html: parse.sld parse/parse.scm parse/repl.scm parse/util.scm 42 | edward.buffer.html: buffer.sld buffer/buffer.scm buffer/stack.scm 43 | 44 | deploy: index.html style.css $(SCMDOC_FILES) 45 | rsync $^ magnesium:/var/www/htdocs/files.8pit.net/edward/latest/doc 46 | 47 | VPATH = ../lib 48 | .PHONY: all clean deploy 49 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # API Documentation 2 | 3 | This generates the API documentation for the edward library interface. 4 | 5 | ## Dependencies 6 | 7 | In order to generate the documentation the following packages need to be installed: 8 | 9 | * [GNU make][gnu make] 10 | * [Discount][discount web] 11 | * [scmdoc][scmdoc github] 12 | 13 | ## Usage 14 | 15 | After installing the aforementioned dependency, run the following command: 16 | 17 | $ make -C doc 18 | 19 | This will generate several HTML files which provide an API documentation for R7RS libraries provided by edward. 20 | An index page which links to these files is also generated. 21 | Open `doc/index.html` in your favorite web browser to view this index page. 22 | 23 | [gnu make]: https://www.gnu.org/software/make 24 | [discount web]: http://www.pell.portland.or.us/~orc/Code/discount/ 25 | [scmdoc github]: https://github.com/nmeum/scmdoc 26 | -------------------------------------------------------------------------------- /doc/index.md: -------------------------------------------------------------------------------- 1 | % Edward API 2 | % author(s) 3 | % date 4 | 5 | # Edward Documentation 6 | 7 | This is the API documentation for the extensible [edward][edward github] text editor. 8 | 9 | ## Libraries 10 | 11 | The edward [CHICKEN][chicken web] [egg][chicken eggs] provides the following R7RS libraries: 12 | 13 | * [(edward ed editor)][edward editor]: The central text editor abstraction. 14 | * [(edward ed cmd)][edward cmd]: Marcos for defining new editor commands. 15 | * [(edward ed posix)][edward posix]: The implementation of POSIX editor commands. 16 | * [(edward ed addr)][edward addr]: Implementation of POSIX ed addressing. 17 | * [(edward parse)][edward parse]: The edward parser combinator library. 18 | * [(edward cli)][edward cli]: The command line interface abstraction. 19 | * [(edward replace)][edward replace]: Implementation of regex replacements. 20 | * [(edward util)][edward util]: Various utility procedures. 21 | * [(edward buffer)][edward buffer]: Line buffer implementation used internally. 22 | 23 | [chicken web]: https://call-cc.org 24 | [chicken eggs]: https://wiki.call-cc.org/eggs 25 | [edward github]: https://github.com/nmeum/edward 26 | [r7rs scheme]: https://small.r7rs.org/ 27 | [edward editor]: edward.ed.editor.html 28 | [edward cmd]: edward.ed.cmd.html 29 | [edward addr]: edward.ed.addr.html 30 | [edward posix]: edward.ed.posix.html 31 | [edward cli]: edward.cli.html 32 | [edward util]: edward.util.html 33 | [edward parse]: edward.parse.html 34 | [edward replace]: edward.replace.html 35 | [edward buffer]: edward.buffer.html 36 | -------------------------------------------------------------------------------- /doc/page.theme: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <?theme title?> 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /edward.egg: -------------------------------------------------------------------------------- 1 | ((author "Sören Tempel") 2 | (synopsis "An extensible implementation of the ed text editor as defined in POSIX.1-2008") 3 | (version "1.1.0") 4 | (category tools) 5 | (license "GPLv3") 6 | (platform unix) 7 | (dependencies r7rs srfi-1 srfi-14 srfi-37 matchable posix-regex) 8 | (test-dependencies test) 9 | (component-options (csc-options "-d3" "-O3" "-X" "r7rs" "-R" "r7rs")) 10 | (cond-expand 11 | (package 12 | (component-options 13 | ;; need static linkange for program component, dynamic for tests 14 | (linkage dynamic static))) 15 | (else 16 | (component-options 17 | ;; don't build static libraries to reduce compile time 18 | (linkage dynamic)))) 19 | (components 20 | (extension edward.util 21 | (source "./lib/util.sld") 22 | (source-dependencies 23 | "./lib/util.scm")) 24 | (extension edward.parse 25 | (component-dependencies edward.util) 26 | 27 | (source "./lib/parse.sld") 28 | (source-dependencies 29 | "./lib/parse/parse.scm" 30 | "./lib/parse/util.scm" 31 | "./lib/parse/repl.scm")) 32 | (extension edward.replace 33 | (component-dependencies edward.parse) 34 | 35 | (source "./lib/replace.sld") 36 | (source-dependencies 37 | "./lib/replace.scm")) 38 | (extension edward.buffer 39 | (component-dependencies edward.util) 40 | 41 | (source "./lib/buffer.sld") 42 | (source-dependencies 43 | "./lib/buffer/stack.scm" 44 | "./lib/buffer/srfi214-minimal.scm" 45 | "./lib/buffer/buffer.scm")) 46 | (extension edward.ed.addr 47 | (component-dependencies edward.parse) 48 | 49 | (source "./lib/ed/addr.sld") 50 | (source-dependencies 51 | "./lib/ed/addr.scm")) 52 | (extension edward.ed.editor 53 | (component-dependencies 54 | edward.util 55 | edward.parse 56 | edward.replace 57 | edward.buffer 58 | edward.ed.addr) 59 | 60 | (source "./lib/ed/editor.sld") 61 | (source-dependencies 62 | "./lib/ed/editor.scm")) 63 | (extension edward.ed.cmd 64 | (component-dependencies 65 | edward.util 66 | edward.parse 67 | edward.ed.addr 68 | edward.ed.editor) 69 | 70 | (source "./lib/ed/cmd.sld") 71 | (source-dependencies 72 | "./lib/ed/cmd.scm")) 73 | (extension edward.ed.posix 74 | (component-dependencies 75 | edward.util 76 | edward.parse 77 | edward.replace 78 | edward.ed.cmd 79 | edward.ed.addr 80 | edward.ed.editor) 81 | 82 | (source "./lib/ed/posix.sld") 83 | (source-dependencies 84 | "./lib/ed/posix.scm")) 85 | (extension edward.cli 86 | (component-dependencies 87 | edward.ed.cmd 88 | edward.ed.posix 89 | edward.ed.editor) 90 | 91 | (source "./lib/cli.sld") 92 | (source-dependencies 93 | "./lib/cli.scm")) 94 | (program bin/edward 95 | ;; In package mode, link statically against Egg dependencies. 96 | (cond-expand 97 | (package 98 | (linkage static)) 99 | (else 100 | (linkage dynamic))) 101 | ;; Uncomment to also link against C libraries statically. 102 | ;(link-options "-L" "-static") 103 | 104 | (install-name "edward") 105 | (component-dependencies edward.cli)))) 106 | -------------------------------------------------------------------------------- /edward.release-info: -------------------------------------------------------------------------------- 1 | (repo git "https://github.com/nmeum/{egg-name}.git") 2 | 3 | (uri targz "https://codeload.github.com/nmeum/{egg-name}/tar.gz/{egg-release}") 4 | (release "1.0.1") 5 | (release "1.1.0") 6 | -------------------------------------------------------------------------------- /lib/buffer.sld: -------------------------------------------------------------------------------- 1 | ;;> A text buffer for line-based data with [undo support][undo section]. 2 | ;;> Operations on the buffer address lines, the first line starts at 3 | ;;> index 1. The special index 0 can be used with the [append command][append command] 4 | ;;> to insert text before the first line. For other commands, index 0 is 5 | ;;> equivalent to index 1. Targeting a line outside the current buffer 6 | ;;> bounds causes an error to be raised. 7 | ;;> 8 | ;;> [undo section]: #section-undo-stack 9 | ;;> [append command]: #buffer-append! 10 | 11 | (define-library (edward.buffer) 12 | (import (scheme base) 13 | (scheme case-lambda) 14 | 15 | (srfi 1) 16 | 17 | (only (chicken base) vector-resize) 18 | 19 | (edward util)) 20 | 21 | (export make-buffer buffer->list buffer-length buffer-empty? buffer-ref 22 | buffer-append! buffer-remove! buffer-with-undo buffer-has-undo? 23 | buffer-undo! buffer-replace! buffer-join! buffer-move!) 24 | 25 | (include "buffer/stack.scm" 26 | "buffer/srfi214-minimal.scm" 27 | "buffer/buffer.scm")) 28 | -------------------------------------------------------------------------------- /lib/buffer/buffer.scm: -------------------------------------------------------------------------------- 1 | ;;>| Buffer Interface 2 | ;;> 3 | ;;> Procedures for creating new buffers and related accessors. 4 | 5 | (define-record-type Line-Buffer 6 | (%make-buffer lines undo? undo-stack) 7 | line-buffer? 8 | (lines buffer-lines) 9 | (undo? buffer-undo? buffer-undo-set!) 10 | (undo-stack buffer-undo-stack buffer-undo-stack-set!)) 11 | 12 | ;;> Create a new, initially empty, line buffer. 13 | 14 | (define (make-buffer) 15 | (%make-buffer (flexvector) #f (make-stack))) 16 | 17 | ;;> Returns the element at `index` in the `buffer`, starting at zero. 18 | 19 | (define (buffer-ref buffer index) 20 | (flexvector-ref (buffer-lines buffer) index)) 21 | 22 | ;;> Convert the line buffer to a list of lines. Additionally, this 23 | ;;> procedure accepts an optional `start` and `end` parameter. If 24 | ;;> these parameters are given the list only contains the elements 25 | ;;> between `start` and `end`. By default the whole buffer is converted. 26 | 27 | (define (buffer->list buffer . o) 28 | (apply flexvector->list (buffer-lines buffer) o)) 29 | 30 | ;;> Length of the buffer, i.e. amount of lines currently stored in it. 31 | 32 | (define (buffer-length buffer) 33 | (flexvector-length (buffer-lines buffer))) 34 | 35 | ;;> Predicate which returns true if the buffer is empty. 36 | 37 | (define (buffer-empty? buffer) 38 | (zero? (buffer-length buffer))) 39 | 40 | (define (buffer-register-undo buffer proc) 41 | (when (buffer-undo? buffer) 42 | (stack-push (buffer-undo-stack buffer) proc))) 43 | 44 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 45 | 46 | ;;>| Undo Stack 47 | ;;> 48 | ;;> Procedures for managing the undo stack of the line buffer. 49 | ;;> The undo stack does not support multilevel undo. 50 | ;;> That is, the last undo can itself be undone using [buffer-undo!](#buffer-undo!). 51 | 52 | ;;> Execute the given `thunk` and make all `buffer` operations performed 53 | ;;> in thunk undoable. 54 | 55 | (define (buffer-with-undo buffer thunk) 56 | (stack-clear! (buffer-undo-stack buffer)) ;; no multi-level undo 57 | (buffer-undo-set! buffer #t) 58 | 59 | (guard 60 | (eobj 61 | (else 62 | (buffer-undo-set! buffer #f) 63 | (raise eobj))) 64 | (let ((r (thunk))) 65 | (buffer-undo-set! buffer #f) 66 | r))) 67 | 68 | ;;> Predicate to check if the undo stack is empty, returns false if it is. 69 | 70 | (define (buffer-has-undo? buffer) 71 | (not (stack-empty? (buffer-undo-stack buffer)))) 72 | 73 | ;;> Revert last operation tracked by [buffer-with-undo](#buffer-with-undo). 74 | ;;> The undo is itself reversible via [buffer-undo!](#buffer-undo!). 75 | 76 | (define (buffer-undo! buffer) 77 | (define (%buffer-undo! buffer procs) 78 | (buffer-with-undo buffer 79 | (lambda () 80 | (for-each (lambda (proc) 81 | (proc buffer)) 82 | procs)))) 83 | 84 | (let* ((stk (buffer-undo-stack buffer)) 85 | (stksiz (stack-size stk))) 86 | (unless (zero? stksiz) 87 | (let ((procs (stack-pops stk stksiz))) 88 | (%buffer-undo! buffer procs))))) 89 | 90 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 91 | 92 | ;;>| Buffer Operations 93 | ;;> 94 | ;;> Procedures which modify the buffer content. 95 | ;;> All operations can be undone using [buffer-undo!](#buffer-undo!). 96 | 97 | ;;> Append the given `text` to the `buffer` after the given `line` number. 98 | ;;> The special line number 0 can be used here to add lines to the 99 | ;;> beginning of the buffer. 100 | 101 | (define (buffer-append! buffer line text) 102 | (flexvector-add-all! (buffer-lines buffer) line text) 103 | (buffer-register-undo buffer 104 | (lambda (buffer) 105 | ;; Will add an undo procedure to the stack, thus making 106 | ;; the undo of the append operation itself reversible. 107 | (buffer-remove! buffer (inc line) (+ line (length text)))))) 108 | 109 | ;;> Removes all lines within the `buffer` at the given inclusive range 110 | ;;> range between `start` and `end`. 111 | 112 | (define (buffer-remove! buffer start end) 113 | (let* ((lines (buffer-lines buffer)) 114 | (sline (max (dec start) 0)) 115 | (bkvec (flexvector->list lines sline end))) 116 | (flexvector-remove-range! (buffer-lines buffer) sline end) 117 | (buffer-register-undo buffer 118 | (lambda (buffer) 119 | ;; Will add an undo procedure to the stack, thus making 120 | ;; the undo of the remove operation itself reversible. 121 | (buffer-append! buffer sline bkvec))))) 122 | 123 | ;; The following operations are all implemented in terms of 124 | ;; buffer-append! and buffer-undo! and are therefore reversible. 125 | 126 | ;;> Replace lines in the inclusive range between `start` and `end` 127 | ;;> with the data given by `text` which must be a list of lines 128 | ;;> (i.e. strings). 129 | 130 | (define (buffer-replace! buffer start end text) 131 | (let* ((sline (max (dec start) 0)) 132 | (cap (- (buffer-length buffer) sline))) 133 | (buffer-remove! buffer start end) 134 | (buffer-append! buffer sline text))) 135 | 136 | ;;> Join lines in the inclusive range between `start` and `end` 137 | ;;> into a single line by removing all newline characters within 138 | ;;> the specified range. 139 | 140 | (define (buffer-join! buffer start end) 141 | (let* ((lines (buffer-lines buffer)) 142 | (sindex (max (dec start) 0)) 143 | (joined (apply 144 | string-append 145 | "" (flexvector->list lines sindex end)))) 146 | (buffer-remove! buffer start end) 147 | (buffer-append! 148 | buffer 149 | sindex 150 | (list joined)))) 151 | 152 | ;;> Move lines in the inclusive range between `start` and `end` 153 | ;;> to the destination line number `dest`. The destination *must* 154 | ;;> always be outside the specified inclusive range. 155 | 156 | (define (buffer-move! buffer start end dest) 157 | ;; Assumption: dest is always outside [start, end]. 158 | (let* ((lines (buffer-lines buffer)) 159 | (sindex (max (dec start) 0)) 160 | (move (flexvector->list lines sindex end)) 161 | 162 | (remove! (lambda () (buffer-remove! buffer start end))) 163 | (append! (lambda () (buffer-append! buffer dest move)))) 164 | (if (> dest start) 165 | (begin (append!) (remove!)) 166 | (begin (remove!) (append!))))) 167 | -------------------------------------------------------------------------------- /lib/buffer/srfi214-minimal.scm: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) 2020-2021 Adam Nelson. 2 | ;; 3 | ;; Permission is hereby granted, free of charge, to any person obtaining a copy 4 | ;; of this software and associated documentation files (the "Software"), to 5 | ;; deal in the Software without restriction, including without limitation the 6 | ;; rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | ;; sell copies of the Software, and to permit persons to whom the Software is 8 | ;; furnished to do so, subject to the following conditions: 9 | ;; 10 | ;; The above copyright notice and this permission notice (including the next 11 | ;; paragraph) shall be included in all copies or substantial portions of the 12 | ;; Software. 13 | ;; 14 | ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | ;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | ;; IN THE SOFTWARE. 21 | 22 | (define-record-type Flexvector 23 | (%make-flexvector fv-vector fv-length) 24 | flexvector? 25 | (fv-vector vec set-vec!) 26 | (fv-length flexvector-length set-flexvector-length!)) 27 | 28 | (define (grow! fv) 29 | (define old-vec (vec fv)) 30 | (define 31 | new-vec 32 | (vector-resize old-vec (quotient (* (vector-length old-vec) 3) 2))) 33 | (set-vec! fv new-vec) 34 | new-vec) 35 | 36 | (define (flexvector) 37 | (%make-flexvector (make-vector 4) 0)) 38 | 39 | (define (flexvector-ref fv index) 40 | (vector-ref (vec fv) index)) 41 | 42 | (define (flexvector-add-all! fv i xs) 43 | (let* ((len (flexvector-length fv)) 44 | (xv (list->vector xs)) 45 | (xvlen (vector-length xv)) 46 | (v (let lp ((v (vec fv))) 47 | (if (< (+ len xvlen) (vector-length v)) v (lp (grow! fv)))))) 48 | (vector-copy! v (+ i xvlen) v i len) 49 | (vector-copy! v i xv 0 xvlen) 50 | (set-flexvector-length! fv (+ len xvlen)) 51 | fv)) 52 | 53 | (define (flexvector-remove-range! fv start end) 54 | (let ((len (flexvector-length fv))) 55 | (when (< start 0) (set! start 0)) 56 | (when (>= end len) (set! end len)) 57 | (vector-copy! (vec fv) start (vec fv) end) 58 | (let ((new-len (- len (- end start)))) 59 | (vector-fill! (vec fv) #f new-len len) 60 | (set-flexvector-length! fv new-len))) 61 | fv) 62 | 63 | ;; Inspired by chez-scheme's SRFI 214 flexvector->list implementation. 64 | (define (%flexvector->list fv start end) 65 | (if (< end start) 66 | (error "invalid sublist specification") 67 | (let ((vec (vec fv))) 68 | (let lp ((acc '()) (idx (dec end))) 69 | (if (< idx start) 70 | acc 71 | (lp (cons (vector-ref vec idx) acc) 72 | (dec idx))))))) 73 | 74 | (define flexvector->list 75 | (case-lambda 76 | ((fv) 77 | (flexvector->list fv 0 (flexvector-length fv))) 78 | ((fv start) 79 | (flexvector->list fv start (flexvector-length fv))) 80 | ((fv start end) 81 | (%flexvector->list fv start end)))) 82 | -------------------------------------------------------------------------------- /lib/buffer/stack.scm: -------------------------------------------------------------------------------- 1 | (define-record-type Stack 2 | (%make-stack store) 3 | stack? 4 | (store stack-store stack-store-set!)) 5 | 6 | (define (make-stack) 7 | (%make-stack '())) 8 | 9 | (define (stack-clear! stack) 10 | (stack-store-set! stack '())) 11 | 12 | (define (stack-size stack) 13 | (length (stack-store stack))) 14 | 15 | (define (stack-empty? stack) 16 | (zero? (stack-size stack))) 17 | 18 | (define (stack-push stack elem) 19 | (stack-store-set! 20 | stack 21 | (cons elem (stack-store stack)))) 22 | 23 | (define (stack-pop stack) 24 | (let* ((lst (stack-store stack)) 25 | (top (car lst))) 26 | (stack-store-set! stack (cdr lst)) 27 | top)) 28 | 29 | (define (stack-pops stack amount) 30 | (if (<= amount 1) 31 | (list (stack-pop stack)) 32 | (cons 33 | (stack-pop stack) 34 | (stack-pops stack (dec amount))))) 35 | -------------------------------------------------------------------------------- /lib/cli.scm: -------------------------------------------------------------------------------- 1 | (define prompt "") 2 | (define silent? #f) 3 | 4 | (define (err msg) 5 | (let ((port (current-error-port))) 6 | (display "edward: " port) 7 | (display msg port) 8 | (newline port))) 9 | 10 | (define prompt-opt 11 | (option 12 | '(#\p "prompt") #t #f 13 | (lambda (o n x vals) 14 | (set! prompt x) 15 | vals))) 16 | 17 | (define silent-opt 18 | (option 19 | '(#\s "silent") #f #f 20 | (lambda (o n x vals) 21 | (set! silent? #t) 22 | vals))) 23 | 24 | (define (parse-args args flags) 25 | (reverse 26 | (args-fold 27 | args 28 | flags 29 | (lambda (o n x vals) 30 | (error "unrecognized option" n)) 31 | cons 32 | '()))) 33 | 34 | (define (run-editor filename) 35 | (let ((editor (make-text-editor exec-edit filename prompt silent?))) 36 | (editor-start editor (parse-cmd)))) 37 | 38 | ;;> Entry point of the edward text editor. This function parses the 39 | ;;> provided command line arguments `args` and starts the 40 | ;;> read-eval-print loop. This command should therefore only be called 41 | ;;> after registering all editor commands. 42 | 43 | (define (edward-main . args) 44 | (let* ((flags (list prompt-opt silent-opt)) 45 | (argv (if (null? args) (command-line) args)) 46 | (files (cdr (parse-args argv flags)))) 47 | (if prompt 48 | (case (length files) 49 | ((1) (run-editor (car files))) 50 | ((0) (run-editor "")) 51 | (else (err "specify one file or no files"))) 52 | (err "missing prompt option argument")))) 53 | -------------------------------------------------------------------------------- /lib/cli.sld: -------------------------------------------------------------------------------- 1 | ;;> Library implementing the edward command line interface. 2 | ;;> Most importantly, this library is responsible for parsing 3 | ;;> the command line options mandated by [POSIX][ed options] 4 | ;;> and afterward starts the read-eval-print loop of the editor. 5 | ;;> 6 | ;;> [ed options]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ed.html#tag_20_38_04 7 | 8 | (define-library (edward.cli) 9 | (import (scheme base) 10 | (scheme write) 11 | (scheme process-context) 12 | 13 | (srfi 37) 14 | 15 | (edward ed cmd) 16 | (edward ed posix) 17 | (edward ed editor)) 18 | 19 | (export edward-main) 20 | 21 | (include "cli.scm")) 22 | -------------------------------------------------------------------------------- /lib/ed/addr.sld: -------------------------------------------------------------------------------- 1 | ;;> This library provides an abstraction for parsing, representing, and 2 | ;;> operating on [ed addresses][ed addresses]. Conceptually, the library 3 | ;;> distinguishes single addresses and ranges. The latter consisting of a 4 | ;;> start and end address as well as a address separator (as defined in 5 | ;;> POSIX). The [parse-addrs][parse-addrs] procedure returns a list of 6 | ;;> address ranges. The editor implementation is capable of converting 7 | ;;> this list to a pair of line numbers using the [addrlst->lpair][addrlst->lpair] 8 | ;;> procedure. Command implementations expecting a range address receive 9 | ;;> this pair, commands which only expect a single address only receive 10 | ;;> the last element of the pair as an argument. 11 | ;;> 12 | ;;> [parse-addrs]: #parse-addrs 13 | ;;> [addrlst->lpair]: edward.ed.editor.html#addrlst->lpair 14 | ;;> [ed addresses]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ed.html#tag_20_38_13_02 15 | 16 | (define-library (edward.ed.addr) 17 | (import (scheme base) 18 | (scheme case-lambda) 19 | 20 | (srfi 1) 21 | (srfi 14) 22 | 23 | (matchable) 24 | 25 | (edward parse)) 26 | 27 | (export make-addr make-range range? addr->range range->addr 28 | parse-addrs parse-addr-with-off expand-addr address-separator?) 29 | 30 | (include "addr.scm")) 31 | -------------------------------------------------------------------------------- /lib/ed/cmd.sld: -------------------------------------------------------------------------------- 1 | ;;> Library for defining custom ed editor commands through provided 2 | ;;> macros. For each command, a parser and an executor needs to be defined. 3 | ;;> The parser is defined using edward [parser combinators][edward parse]. 4 | ;;> The executor receives an [editor object][editor object] as well as the 5 | ;;> return value of the parser combinator as procedure arguments and modifies 6 | ;;> the editor state accordingly. Additionally, this library defines several 7 | ;;> utility procedures that are useful for defining [executor procedures][executor util] 8 | ;;> and ed [parser combinators][parser util]. 9 | ;;> 10 | ;;> [edward parse]: edward.parse.html 11 | ;;> [editor object]: edward.ed.editor.html#section-text-editor-object 12 | ;;> [executor util]: #section-executor-utilities 13 | ;;> [parser util]: #section-parser-utilities 14 | 15 | (define-library (edward.ed.cmd) 16 | (import (scheme base) 17 | (scheme file) 18 | (scheme lazy) 19 | 20 | (srfi 1) 21 | (srfi 14) 22 | 23 | (only (chicken process) call-with-input-pipe call-with-output-pipe) 24 | 25 | (edward util) 26 | (edward parse) 27 | (edward ed addr) 28 | (edward ed editor)) 29 | 30 | ;; Utility procedures to define custom editor commands. 31 | (export define-edit-cmd define-input-cmd define-print-cmd define-file-cmd 32 | parse-cmd-char parse-cmd parse-re parse-re-pair unwrap-command-list 33 | exec-command-list parse-filename parse-file-cmd write-lines 34 | read-from call-when-confirmed subst-nomatch-handler 35 | filename-cmd? register-command exec-command-list-interactive) 36 | 37 | ;; Editor command executors mandated by POSIX. 38 | (include "cmd.scm")) 39 | -------------------------------------------------------------------------------- /lib/ed/editor.sld: -------------------------------------------------------------------------------- 1 | ;;> This library implements a [text editor object][section text-editor] 2 | ;;> which tracks an internal state that can be modified through defined 3 | ;;> [editor operations][section operations]. These operations operate on 4 | ;;> a pair of line numbers. POSIX [ed addresses][edward ed addr] can be 5 | ;;> translated to a pair of line numbers using 6 | ;;> [address translation][section translation] procedures described below. 7 | ;;> 8 | ;;> [section text-editor]: #section-text-editor-object 9 | ;;> [section operations]: #section-editor-operations 10 | ;;> [section translation]: #section-address-translation 11 | ;;> [edward ed addr]: edward.ed.addr.html 12 | ;;> [range->lpair]: #range->lpair 13 | 14 | (define-library (edward.ed.editor) 15 | (import (scheme base) 16 | (scheme file) 17 | (scheme case-lambda) 18 | (scheme process-context) 19 | 20 | (srfi 1) 21 | 22 | (matchable) 23 | (posix-regex) 24 | 25 | (only (chicken process signal) signal-mask! 26 | signal/quit signal/hup set-signal-handler!) 27 | (only (chicken port) terminal-port?) 28 | 29 | (edward util) 30 | (edward parse) 31 | (edward buffer) 32 | (edward ed addr)) 33 | 34 | (export make-text-editor text-editor? text-editor-prevcmd 35 | text-editor-modified? text-editor-filename 36 | text-editor-filename-set! text-editor-modified-set! 37 | text-editor-help? text-editor-help-set! 38 | text-editor-line text-editor-error 39 | text-editor-last-cmd-set!) 40 | 41 | (export editor-start editor-error editor-filename editor-make-regex 42 | editor-exec-cmdlist editor-mark-line editor-shell-cmd 43 | editor-xexec editor-exec make-cmd editor-cmd? cmd-args editor-raise 44 | editor-goto! editor-interactive editor-restr editor-verbose 45 | editor-reset! editor-get-lnum editor-get-lines editor-in-range? 46 | editor-undo! editor-lines editor-append! editor-replace! 47 | editor-join! editor-remove! editor-move! editor-line-numbers 48 | addr->line range->lpair editor-toggle-prompt! addrlst->lpair) 49 | 50 | (include "editor.scm")) 51 | -------------------------------------------------------------------------------- /lib/ed/posix.sld: -------------------------------------------------------------------------------- 1 | ;;> This library implements the editor commands mandated by the 2 | ;;> [POSIX.1-2008 ed(1)][posix commands] specification. This is achieved 3 | ;;> by leveraging the [edward ed cmd][edward ed cmd] abstraction. The 4 | ;;> executor for all POSIX ed commands is exported and can be reused to 5 | ;;> implement new commands. 6 | ;;> 7 | ;;> [posix commands]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ed.html#tag_20_38_13_03 8 | ;;> [edward ed cmd]: edward.ed.cmd.html 9 | 10 | (define-library (edward.ed.posix) 11 | (import (scheme base) 12 | (scheme write) 13 | (scheme process-context) 14 | 15 | (srfi 1) 16 | (srfi 14) 17 | 18 | (posix-regex) 19 | (matchable) 20 | 21 | (only (chicken process) system) 22 | (only (chicken string) string-split) 23 | 24 | (edward util) 25 | (edward parse) 26 | (edward replace) 27 | (edward ed cmd) 28 | (edward ed addr) 29 | (edward ed editor)) 30 | 31 | (export %exec-edit %exec-quit exec-append exec-change exec-command 32 | exec-copy exec-delete exec-edit exec-filename exec-global 33 | exec-help exec-insert exec-interactive exec-join 34 | exec-line-number exec-list exec-mark exec-move exec-null 35 | exec-number exec-print exec-prompt exec-quit exec-read 36 | exec-subst exec-undo exec-write) 37 | 38 | (include "posix.scm")) 39 | -------------------------------------------------------------------------------- /lib/parse.sld: -------------------------------------------------------------------------------- 1 | ;;> This is a stripped-down and minimally modified version of [chibi parse][chibi parse], 2 | ;;> a parser combinator library with optional memoization. This version of the library 3 | ;;> is specifically designed to faciliate building read-eval-print loops with parser 4 | ;;> combinators. 5 | ;;> 6 | ;;> Apart from [parse streams][stream section], the central abstraction of this libary 7 | ;;> is therefore a [REPL][repl section] type which continously reads data from standard 8 | ;;> input and parses this data with parsers constructed using provided parser combinators. 9 | ;;> 10 | ;;> An exemplary parser may be constructed as follows: 11 | ;;> 12 | ;;> ``` 13 | ;;> (import (srfi 14) (edward parse)) 14 | ;;> 15 | ;;> (define hexadecimal 16 | ;;> (parse-map 17 | ;;> (parse-seq 18 | ;;> (parse-string "0x") 19 | ;;> (parse-map 20 | ;;> (parse-token char-set:hex-digit) 21 | ;;> (lambda (str) 22 | ;;> (string->number str 16)))) 23 | ;;> cadr)) 24 | ;;> ``` 25 | ;;> 26 | ;;> This parser recognizes hexadecimal integers using the character set definition 27 | ;;> provided by [SRFI 14][srfi 14] and transform these characters into a Scheme 28 | ;;> number type using [parse-map][parse-map]. Refer to the documentation below 29 | ;;> for more information on available combinators. 30 | ;;> 31 | ;;> [chibi parse]: https://synthcode.com/scheme/chibi/lib/chibi/parse.html 32 | ;;> [stream section]: #section-parse-streams 33 | ;;> [repl section]: #section-read–eval–print-loop 34 | ;;> [srfi 14]: https://srfi.schemers.org/srfi-14/srfi-14.html 35 | ;;> [parse-map]: #parse-map 36 | 37 | (define-library (edward.parse) 38 | (import (scheme base) 39 | (scheme char) 40 | (scheme file) 41 | (scheme write) 42 | 43 | (srfi 1) 44 | (srfi 14) 45 | 46 | (edward util) 47 | 48 | (only (chicken file posix) file-read file-close fileno/stdin) 49 | (only (chicken process signal) set-signal-handler! signal/int)) 50 | 51 | ;; repl.scm 52 | (export make-repl repl? repl-run repl-interactive repl-prompt? repl-set-prompt!) 53 | 54 | ;; parse.scm 55 | (export call-with-parse parse parse-fully parse-fold parse-failure 56 | parse->list parse-fully->list 57 | file->parse-stream string->parse-stream parse-stream-substring 58 | parse-stream-start? parse-stream-end? parse-stream-ref 59 | parse-anything parse-nothing parse-epsilon 60 | parse-seq parse-and parse-or parse-not list->parse-seq 61 | parse-repeat parse-repeat+ parse-optional 62 | parse-map parse-map-substring parse-ignore parse-assert 63 | parse-atomic parse-commit parse-lazy parse-memoize 64 | parse-char parse-not-char 65 | parse-string parse-token 66 | parse-beginning parse-end 67 | parse-beginning-of-line parse-end-of-line 68 | parse-with-failure-reason 69 | make-parse-stream) 70 | 71 | ;; parse-util.scm 72 | (export parse-fail parse-bind parse-as-string parse-digits parse-lowercase 73 | parse-default parse-newline parse-blank 74 | parse-blanks+ parse-blanks parse-between parse-esc 75 | parse-strip-blanks parse-blanks-seq parse-line parse-alist 76 | parse-with-context parse-regex-lit* parse-regex-lit) 77 | 78 | (include "parse/repl.scm" 79 | "parse/parse.scm" 80 | "parse/util.scm")) 81 | -------------------------------------------------------------------------------- /lib/parse/repl.scm: -------------------------------------------------------------------------------- 1 | ;;>| Read–Eval–Print Loop 2 | ;;> 3 | ;;> REPL abstraction which provides a read-eval-print loop that 4 | ;;> continously reads data from standard input and parses this 5 | ;;> input data using provided parser combinators. The REPL 6 | ;;> operates on a [parse stream](#section-parse-streams) internally. 7 | 8 | ;;> Create an new REPL instance with the given input `prompt` string. 9 | 10 | (define (make-repl prompt) 11 | (let ((prompt? (not (empty-string? prompt)))) 12 | (%make-repl 13 | (if prompt? prompt "*") 14 | prompt? 15 | (make-parse-stream "stdin" fileno/stdin) 16 | 0))) 17 | 18 | (define (repl-state-set! repl source index) 19 | (repl-stream-set! repl source) 20 | (repl-index-set! repl index)) 21 | 22 | ;;> Record type representing the REPL. 23 | (define-record-type Read-Eval-Print-Loop 24 | (%make-repl prompt-str prompt? stream index) 25 | ;;> Predicate which returns true if the given object was created using [make-repl](#make-repl). 26 | repl? 27 | ;; Prompt string used for input prompt. 28 | (prompt-str repl-prompt-str) 29 | ;; Whether the prompt should be shown or hidden. 30 | (prompt? 31 | ;;> Predicate which returns true if the prompt should be shown. 32 | repl-prompt? 33 | 34 | ;;> Change prompt visibility, a truth value means the prompt is shown. 35 | repl-set-prompt!) 36 | ;; Parse stream used for the parser combinator. 37 | (stream repl-stream repl-stream-set!) 38 | ;; Last index in parse stream. 39 | (index repl-index repl-index-set!)) 40 | 41 | ;; Skip all buffered chunks, i.e. next read will block. 42 | 43 | (define (repl-skip-chunks! repl) 44 | (define (%repl-skip-chunks! source i) 45 | (if (>= (+ i 1) (vector-length (parse-stream-buffer source))) 46 | (%repl-skip-chunks! (parse-stream-tail source) i) ;; go to last chunck 47 | (values 48 | source 49 | ;; inc to go beyond last char. 50 | (inc (parse-stream-max-char source))))) 51 | 52 | (let-values (((source i) 53 | (%repl-skip-chunks! 54 | (repl-stream repl) 55 | (repl-index repl)))) 56 | (repl-state-set! repl source i))) 57 | 58 | (define (repl-parse repl f sk fk) 59 | (define (stream-next-line source idx) 60 | (let* ((next-index (parse-stream-next-index source idx)) 61 | (next-source (parse-stream-next-source source idx)) 62 | (char (parse-stream-ref source idx))) 63 | (if (or (eof-object? char) (char=? char #\newline)) 64 | (cons next-source next-index) ;; first index after newline/eof 65 | (stream-next-line 66 | next-source 67 | next-index)))) 68 | 69 | (call-with-parse f 70 | (repl-stream repl) 71 | (repl-index repl) 72 | (lambda (r s i fk) 73 | (repl-state-set! repl s i) 74 | (sk (repl-line repl i) r)) 75 | (lambda (s i reason) 76 | (let ((line (repl-line repl i)) 77 | (next (stream-next-line (repl-stream repl) i))) 78 | (repl-state-set! repl (car next) (cdr next)) 79 | (fk line reason))))) 80 | 81 | (define (repl-line repl index) 82 | (let ((s (repl-stream repl))) 83 | (inc ;; XXX: For some reason line start at zero. 84 | (+ 85 | (parse-stream-line s) 86 | (car (parse-stream-count-lines s (parse-stream-max-char s))))))) 87 | 88 | ;;> Start the REPL given by `repl`, and continuously parse input using 89 | ;;> the provided parser `f`. Successfully parsed input is passed to 90 | ;;> the success continuation `sk`, which receives the line number and 91 | ;;> parser result as procedure arguments. If the parser failed for the 92 | ;;> current input, the failure continuation `fk` is invoked. This 93 | ;;> continuation receives the line number and failure reason as 94 | ;;> procedure arguments. Lastly, an interrupt continuation must 95 | ;;> also be provided which is invoked on `SIGINT`. This continuation 96 | ;;> is not passed any arguments. 97 | 98 | (define (repl-run repl f sk fk ik) 99 | (when (repl-prompt? repl) 100 | (display (repl-prompt-str repl)) 101 | (flush-output-port)) 102 | 103 | ;; Allow parsing itself (especially of input mode commands) to be 104 | ;; interrupted by SIGINT signals. See "Asynchronous Events" in ed(1). 105 | (call-with-current-continuation 106 | (lambda (k) 107 | (set-signal-handler! 108 | signal/int 109 | (lambda (signum) 110 | (ik) 111 | (repl-skip-chunks! repl) 112 | (k #f))) 113 | 114 | (begin 115 | (repl-parse repl f sk fk) 116 | (k #f)))) 117 | 118 | (repl-run repl f sk fk ik)) 119 | 120 | ;;> Run a parser interactively within the REPL. That is, deviate from 121 | ;;> the standard REPL parser and instead parse the next input line 122 | ;;> with the given parser `f`. On success, returns the result of `f` 123 | ;;> otherwise, invokes the provided failure continuation `fk`. 124 | 125 | (define (repl-interactive repl f fk) 126 | (repl-parse repl f (lambda (line value) value) fk)) 127 | -------------------------------------------------------------------------------- /lib/parse/util.scm: -------------------------------------------------------------------------------- 1 | ;;>| Utility Parsing Combinators 2 | ;;> 3 | ;;> Additional high-level combinators implemented using the aforementioned 4 | ;;> [basic combinators][basic section]. The provided high-level combinators, 5 | ;;> return more useful parser error messages then the basic ones. 6 | ;;> 7 | ;;> [basic section]: #section-basic-parsing-combinators 8 | 9 | ;;> Parser which always fails with the given error message. 10 | 11 | (define (parse-fail msg) 12 | (lambda (source index sk fk) 13 | (fk source index msg))) 14 | 15 | ;;> Bind a constant `value` to a given `parser`. 16 | ;;> That is, always return this value if the parser succeeds. 17 | 18 | (define (parse-bind value parser) 19 | (parse-map 20 | parser 21 | (lambda (x) value))) 22 | 23 | ;;> Run a parser `f`, which *must* return a list, and convert 24 | ;;> its return value to a string using the `list->string` procedure. 25 | 26 | (define (parse-as-string parser) 27 | (parse-map 28 | parser 29 | list->string)) 30 | 31 | ;;> Parse one or more digits (i.e. `0-9`), interpret them as a 32 | ;;> decimal number, and return this number. 33 | 34 | (define parse-digits 35 | (parse-with-failure-reason 36 | (parse-map 37 | (parse-token char-set:digit) 38 | string->number) 39 | "expected digits")) 40 | 41 | ;;> Parse an ASCII lowercase character (i.e. `a-z`). 42 | 43 | (define parse-lowercase 44 | (parse-with-failure-reason 45 | (parse-char char-set:lower-case) 46 | "expected lowercase character")) 47 | 48 | ;;> Attempt parsing using the given parser `f`, if it fails return a default value `def`. 49 | 50 | (define (parse-default f def) 51 | (parse-map 52 | (parse-optional f) 53 | (lambda (x) 54 | (if x x def)))) 55 | 56 | ;;> Parse a newline character. 57 | 58 | (define parse-newline 59 | (parse-with-failure-reason 60 | (parse-char #\newline) 61 | "expected newline")) 62 | 63 | ;;> Parse a single blank character (i.e. horizontal whitespace). 64 | 65 | (define parse-blank 66 | (parse-with-failure-reason 67 | (parse-char char-set:blank) 68 | "expected whitespace")) 69 | 70 | ;;> Parse one or more blank characters. 71 | 72 | (define parse-blanks+ 73 | (parse-with-failure-reason 74 | (parse-token char-set:blank) 75 | "expected whitespaces")) 76 | 77 | ;;> Parse zero or more blank characters. 78 | 79 | (define parse-blanks 80 | (parse-optional parse-blanks+)) 81 | 82 | ;;> Invokes parser `f` between the parsers `lhs` and `rhs`. 83 | 84 | (define (parse-between lhs f rhs) 85 | (parse-map 86 | (parse-seq lhs f rhs) 87 | cadr)) 88 | 89 | ;;> Returns the result of parser `f` but allows preceding its input 90 | ;;> with a backslash character to escape it in the parsed input format. 91 | 92 | (define (parse-esc f) 93 | (parse-map 94 | (parse-seq 95 | (parse-char #\\) 96 | f) 97 | cadr)) 98 | 99 | ;;> Parse an `alist` mapping chars to values which should be returned for each char. 100 | 101 | (define (parse-alist alist) 102 | (apply 103 | parse-or 104 | (map 105 | (lambda (x) 106 | (parse-map 107 | (parse-char (car x)) 108 | (lambda (_) 109 | (cdr x)))) 110 | alist))) 111 | 112 | ;; Utility procedure for parsing ed(1) BRE addresses. 113 | 114 | (define (%parse-regex-lit ch end) 115 | (parse-with-failure-reason 116 | (parse-atomic 117 | (parse-as-string 118 | (parse-between 119 | (parse-char ch) 120 | (parse-repeat (parse-or 121 | (parse-esc (parse-char ch)) 122 | (parse-char (char-set-complement (char-set ch #\newline))))) 123 | end))) 124 | "expected regex")) 125 | 126 | ;;> Parse a regex literal which is enclosed by the character `ch`. 127 | 128 | (define (parse-regex-lit ch) 129 | (%parse-regex-lit 130 | ch 131 | (parse-char ch))) 132 | 133 | ;;> Parse a regex literal which starts with character `ch` and is 134 | ;;> terminated by the same character or the end of line. 135 | 136 | (define (parse-regex-lit* ch) 137 | (%parse-regex-lit 138 | ch 139 | (parse-or 140 | (parse-char ch) 141 | parse-end-of-line))) 142 | 143 | ;;> Invoke given parser and strip trailing blanks (if any). 144 | 145 | (define (parse-strip-blanks parser) 146 | (parse-map 147 | (parse-seq 148 | parser 149 | parse-blanks) 150 | car)) 151 | 152 | ;;> Like [parse-seq](#parse-seq) but skip blanks *before* each parser. 153 | 154 | (define (parse-blanks-seq . o) 155 | (define (%parse-blanks-seq lst) 156 | (parse-seq-list 157 | (apply append 158 | (zip (make-list 159 | (length lst) 160 | (parse-ignore parse-blanks)) 161 | lst)))) 162 | 163 | (%parse-blanks-seq o)) 164 | 165 | ;;> Parse a single line (excluding the terminating newline character). 166 | 167 | (define parse-line 168 | (parse-atomic 169 | (parse-or 170 | (parse-bind "" parse-newline) ;; empty line 171 | (parse-map 172 | (parse-seq 173 | (parse-token (lambda (x) (not (char=? x #\newline)))) 174 | ;; XXX: parse-end-of-line does _not_ consume the end-of-file. 175 | ;; This is crucial for parse-input-mode to work correctly. 176 | (parse-or parse-newline parse-end-of-line)) 177 | car)))) 178 | 179 | ;;> Feed the result of the parser `ctx` to a single argument procedure `f`. 180 | ;;> The procedure must then return a new parser which is executed 181 | ;;> afterwards on the same index as `ctx`. 182 | 183 | (define (parse-with-context ctx f) 184 | (lambda (source index sk fk) 185 | (let* ((yield (lambda (r s i fk) r)) 186 | (value (call-with-parse ctx source index yield))) 187 | (if value ;; default fk returns #f on error 188 | ((f value) source index sk fk) 189 | (fk source index "context parser failed"))))) 190 | -------------------------------------------------------------------------------- /lib/replace.scm: -------------------------------------------------------------------------------- 1 | ;;>| Replacement Parser 2 | ;;> 3 | ;;> Edward [parser combinators][edward parse] for parsing replacement strings. 4 | ;;> 5 | ;;> [edward parse]: edward.parse.html 6 | 7 | (define parse-backref 8 | (parse-map 9 | (parse-seq 10 | (parse-char #\\) 11 | parse-digits) 12 | (lambda (lst) 13 | (cons 'backref (cadr lst))))) 14 | 15 | (define parse-matched 16 | (parse-map 17 | (parse-char #\&) 18 | (lambda (ch) 19 | (cons 'matched ch)))) 20 | 21 | (define (parse-restr delim) 22 | (define replace-ctrl 23 | (char-set-adjoin (char-set #\\ #\& #\newline) delim)) 24 | 25 | (parse-map 26 | (parse-as-string 27 | (parse-repeat+ 28 | (parse-or 29 | ;; special handling for '%' as it does not neccessarily 30 | ;; need to be escaped unless it's the only character. 31 | (parse-esc 32 | (parse-char (char-set-adjoin replace-ctrl #\%))) 33 | (parse-not-char replace-ctrl)))) 34 | (lambda (str) 35 | (cons 'restr str)))) 36 | 37 | ;;> Parse a replacement string within text enclosed with the delimiter 38 | ;;> `delim`. While the combinator does not parse the enclosed character, 39 | ;;> it ensures that this `delim` character is escaped (using a `\`) 40 | ;;> within the replacement. 41 | ;;> 42 | ;;> Refer to the documentation of the [ed substitute][ed substitute] 43 | ;;> command for more information on special character support within 44 | ;;> the replacement. All of these special characters can also be 45 | ;;> escaped. 46 | ;;> 47 | ;;> [ed substitute]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ed.html#tag_20_38_13_25 48 | 49 | (define (parse-replace delim) 50 | (parse-map 51 | (parse-repeat 52 | (parse-atomic 53 | (parse-or 54 | parse-backref 55 | parse-matched 56 | (parse-restr delim)))) 57 | (lambda (lst) 58 | ;; If the replacement is empty replace matched text with an empty string. 59 | (if (null? lst) 60 | (cons '(restr . "") lst) 61 | lst)))) 62 | 63 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 64 | 65 | ;;>| Replacement Procedures 66 | ;;> 67 | ;;> Procedures for performing replacements using a parsed replacement string. 68 | 69 | (define (submatch subm bv n) 70 | (if (>= n (vector-length subm)) 71 | (string->utf8 (number->string n)) ;; XXX: Handling for invalid backreferences 72 | (let ((match (vector-ref subm n))) 73 | (if match 74 | (bytevector-copy bv (car match) (cdr match)) 75 | #u8())))) 76 | 77 | (define (regex-replace* regex subst bv nth) 78 | (define (apply-replacement subm bv replacement) 79 | (fold (lambda (x y) 80 | (bytevector-append y 81 | (match x 82 | (('restr . s) (string->utf8 s)) 83 | (('matched . _) (submatch subm bv 0)) 84 | (('backref . n) (submatch subm bv n))))) 85 | #u8() replacement)) 86 | 87 | ;; TODO: Refactor this function and make it more readable. 88 | ;; Also don't rely on (values …) truncation (not in R7RS). 89 | (define (%regex-replace* re start n) 90 | (let* ((v (bytevector-copy bv start)) 91 | (subm (regex-exec regex v))) 92 | (if subm 93 | (let* ((m (vector-ref subm 0)) ;; submatch for entire regex 94 | (s (car m)) ;; start of submatch 95 | (e (cdr m)) ;; end of submatch 96 | 97 | (i (+ start e)) ;; next index in bv 98 | (r (delay (bytevector-append 99 | (bytevector-copy v 0 s) 100 | (apply-replacement subm v re))))) 101 | (values 102 | (if (eqv? n nth) 103 | (bytevector-append (force r) (bytevector-copy bv i)) 104 | (bytevector-append 105 | (if (zero? nth) (force r) (bytevector-copy v 0 e)) 106 | (%regex-replace* re i (+ n 1)))) 107 | #t)) 108 | (values v #f)))) 109 | 110 | (%regex-replace* subst 0 1)) 111 | 112 | ;;> Replace `nth` occurrence of `regex` in `str` with `subst`. If `nth` 113 | ;;> is zero, all occurrences are replaced. Returns two results: The string 114 | ;;> after performing all replacement and a boolean indicating if any 115 | ;;> replacements were successfully performed. The `regex` must be 116 | ;;> created using [make-regex][make-regex], while the replacement string 117 | ;;> `subst` must be parsed using [parse-replace][parse-replace]. 118 | ;;> 119 | ;;> [make-regex]: https://wiki.call-cc.org/eggref/5/posix-regex#make-regex 120 | ;;> [parse-replace]: #parse-replace 121 | 122 | (define (regex-replace regex subst str nth) 123 | ;; regexec(3p) offsets are byte, not character offsets. 124 | ;; Thus, the string needs to be converted to a bytevector. 125 | (let-values (((result modified) (regex-replace* regex subst (string->utf8 str) nth))) 126 | (values (utf8->string result) modified))) 127 | -------------------------------------------------------------------------------- /lib/replace.sld: -------------------------------------------------------------------------------- 1 | ;;> This library implementes [BRE][bre posix] regex replacements on top 2 | ;;> of the existing [posix-regex][posix-regex egg] library. 3 | ;;> 4 | ;;> [posix-regex egg]: https://wiki.call-cc.org/eggref/5/posix-regex 5 | ;;> [bre posix]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html 6 | 7 | (define-library (edward.replace) 8 | (import (scheme base) 9 | (scheme lazy) 10 | 11 | (srfi 1) 12 | (srfi 14) 13 | 14 | (matchable) 15 | (posix-regex) 16 | 17 | (edward parse)) 18 | 19 | (export parse-replace regex-replace) 20 | 21 | (include "replace.scm")) 22 | -------------------------------------------------------------------------------- /lib/util.scm: -------------------------------------------------------------------------------- 1 | ;;>| String Procedures 2 | ;;> 3 | ;;> Utility procedures which operate on strings. 4 | 5 | ;;> Return true if the given string `str` is the empty string. 6 | 7 | (define (empty-string? str) 8 | (zero? (string-length str))) 9 | 10 | ;;> Pad given string `str` with given padding string `pad` to `length`. 11 | 12 | (define (pad-string str pad length) 13 | (if (>= (string-length str) length) 14 | str 15 | (pad-string (string-append pad str) pad length))) 16 | 17 | ;;> Convert string to a human readable representation as mandated 18 | ;;> by the ed [list command][ed list]. 19 | ;;> 20 | ;;> [ed list]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ed.html#tag_20_38_13_17 21 | 22 | (define (string->human-readable str) 23 | ;; Length at which lines are folded. 24 | (define fold-length 25 | (let*-values (((padding) 8) 26 | ((port) (current-output-port)) 27 | ((_ cols) (if (terminal-port? port) 28 | (terminal-size port) 29 | (values 0 0)))) 30 | (if (> cols padding) 31 | (- cols padding) 32 | 72))) 33 | 34 | (define (byte->human-readable byte) 35 | (case byte 36 | ;; Mapping according to Table 5-1 in POSIX-1.2008. 37 | ((#x5C) "\\\\") 38 | ((#x07) "\\a") 39 | ((#x08) "\\b") 40 | ((#x0C) "\\f") 41 | ((#x0D) "\\r") 42 | ((#x09) "\\t") 43 | ((#x0B) "\\v") 44 | 45 | ;; End of each line shall be marked with a `$` character. 46 | ((#x0A) "$\n") 47 | ;; `$` character within the line should be escaped. 48 | ((#x24) "\\$") 49 | 50 | ;; Non-printable characters are represented in octal. 51 | (else 52 | (if (ascii-printable? byte) 53 | (string (integer->char byte)) 54 | (string-append "\\" (pad-string (number->string byte 8) "0" 3)))))) 55 | 56 | ;; Fold lines at fold-length and convert bytes according to procedure above. 57 | (let ((bv (string->utf8 str))) 58 | (fold (lambda (idx out) 59 | (let* ((byte (bytevector-u8-ref bv idx)) 60 | (ret (string-append out (byte->human-readable byte)))) 61 | (if (and (not (zero? idx)) 62 | (zero? (modulo idx fold-length))) 63 | (string-append ret "\\\n") 64 | ret))) 65 | "" (iota (bytevector-length bv))))) 66 | 67 | ;;> Join a list of path elements (i.e. strings) using `/` as a path separator. 68 | 69 | (define (path-join . elems) 70 | (fold-right 71 | (lambda (elem path) 72 | (if (empty-string? path) 73 | elem 74 | (string-append elem "/" path))) 75 | "" elems)) 76 | 77 | ;;> Return amount of bytes in a string. 78 | 79 | (define (count-bytes str) 80 | ;; Technically, we would have to convert the string to a bytevector here and 81 | ;; then count the length of that bytevector to obtain the number of bytes 82 | ;; and not the number of characters. However, CHICKEN 5 is not fully unicode 83 | ;; aware and hence string-length actually counts bytes and not characters. 84 | ;; 85 | ;; Additionally a string->utf8 conversion is very expensive especially when 86 | ;; loading large files using edward. Therefore, ideally, we would obtain the 87 | ;; amount of bytes directly through the read procedure in the future. 88 | (string-length str)) 89 | 90 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 91 | 92 | ;;>| IO Procedures 93 | ;;> 94 | ;;> Procedures which deal with input/output. 95 | 96 | ;;> Write `lines`, i.e. a list of non-newline terminated strings to a 97 | ;;> given `port`. Returns the amount of bytes written to the port 98 | ;;> (including any newline characters). 99 | 100 | (define (lines->port lines port) 101 | (fold (lambda (line num) 102 | (let ((line (string-append line "\n"))) 103 | (write-string line port) 104 | (+ num (count-bytes line)))) 105 | 0 lines)) 106 | 107 | ;;> Read from given `port` as a list of lines. Returns pair of retrieved 108 | ;;> lines and total amount of bytes read from the port (including 109 | ;;> newlines). 110 | 111 | (define (port->lines port) 112 | (let ((lines (read-lines port))) 113 | (cons 114 | lines 115 | (fold (lambda (l n) 116 | ;; +1 for newline stripped by read-lines. 117 | ;; XXX: Buggy if last line is not not terminated with \n. 118 | (+ 1 n (count-bytes l))) 0 lines)))) 119 | 120 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 121 | 122 | ;;>| Miscellaneous 123 | ;;> 124 | ;;> Miscellaneous utility procedures. 125 | 126 | ;;> Syntactic sugar to increment a number by one. 127 | (define (inc n) (+ n 1)) 128 | ;;> Syntactic sugar to decrement a number by one. 129 | (define (dec n) (- n 1)) 130 | 131 | ;;> Identity function, always returns the given value. 132 | 133 | (define (id x) x) 134 | 135 | ;;> Returns all values of an `alist`, discarding the keys. 136 | 137 | (define (alist-values alist) 138 | (map cdr alist)) 139 | 140 | ;;> Like `display` but prints multiple objects and adds a trailing newline. 141 | 142 | (define (println . objs) 143 | (apply fprintln (current-output-port) objs)) 144 | 145 | ;;> Like [println](#println) but allows specification of a custom output `port`. 146 | 147 | (define (fprintln port . objs) 148 | (for-each (lambda (obj) (display obj port)) objs) 149 | (newline port)) 150 | 151 | ;;> Whether the given `integer` does not represent an ASCII control character. 152 | 153 | (define (ascii-printable? integer) 154 | (and (>= integer #x20) (<= integer #x7e))) 155 | 156 | ;;> Return path to home directory of current user. 157 | ;;> This procedure emits an error if the environment variable `HOME` is unset. 158 | 159 | (define (user-home) 160 | (let ((home (get-environment-variable "HOME"))) 161 | (if home 162 | home 163 | (error "environment variable 'HOME' not set")))) 164 | -------------------------------------------------------------------------------- /lib/util.sld: -------------------------------------------------------------------------------- 1 | ;;> This library provides various generic utility procedures. 2 | 3 | (define-library (edward.util) 4 | (import (scheme base) 5 | (scheme write) 6 | (scheme file) 7 | (scheme process-context) 8 | 9 | (srfi 1) 10 | 11 | (only (chicken port) terminal-port? terminal-size) 12 | (only (chicken io) read-lines)) 13 | 14 | (export inc dec id alist-values fprintln println empty-string? 15 | pad-string string->human-readable path-join user-home 16 | count-bytes lines->port port->lines) 17 | 18 | (include "util.scm")) 19 | -------------------------------------------------------------------------------- /tests/integration/address-chain-eval-order/cmds: -------------------------------------------------------------------------------- 1 | ;1;n 2 | ;,1,;n 3 | -------------------------------------------------------------------------------- /tests/integration/address-chain-eval-order/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/address-chain-eval-order/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | foo 5 | bar 6 | foo 7 | test 8 | foo 9 | -------------------------------------------------------------------------------- /tests/integration/address-chain-fully-eval/cmds: -------------------------------------------------------------------------------- 1 | 3;/foo/;+2p 2 | -------------------------------------------------------------------------------- /tests/integration/address-chain-fully-eval/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/address-chain-fully-eval/testdata/input-file: -------------------------------------------------------------------------------- 1 | this line already contains the string "foo" 2 | however, we only start searching at line 3 3 | <--we start searching here--> 4 | hence "foo" will not be matched before line 3. 5 | line 1 after match 6 | line 2 after match 7 | last line 8 | -------------------------------------------------------------------------------- /tests/integration/address-range-large-address/cmds: -------------------------------------------------------------------------------- 1 | 9223372036854775808,3947209347923759032m256 2 | -------------------------------------------------------------------------------- /tests/integration/address-range-semicolon-list/cmds: -------------------------------------------------------------------------------- 1 | /foo/;+3l 2 | /foo/;+3l 3 | -------------------------------------------------------------------------------- /tests/integration/address-range-semicolon-list/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/address-range-semicolon-list/testdata/input-file: -------------------------------------------------------------------------------- 1 | this line contains the word 'foo' 2 | and aftr this line there are 3 | 5 more lines 4 | which can be printed 5 | by an ed range 6 | 7 | however, this line also has the word 'foo' 8 | but no 5 lines after it, hence causing an error when selected as a range start. 9 | -------------------------------------------------------------------------------- /tests/integration/address-range-semicolon-number/cmds: -------------------------------------------------------------------------------- 1 | /foo/;+5n 2 | /foo/;+5n 3 | -------------------------------------------------------------------------------- /tests/integration/address-range-semicolon-number/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/address-range-semicolon-number/testdata/input-file: -------------------------------------------------------------------------------- 1 | this line contains the word 'foo' 2 | and aftr this line there are 3 | 5 more lines 4 | which can be printed 5 | by an ed range 6 | 7 | however, this line also has the word 'foo' 8 | but no 5 lines after it, hence causing an error when selected as a range start. 9 | -------------------------------------------------------------------------------- /tests/integration/address-range-semicolon-print/cmds: -------------------------------------------------------------------------------- 1 | /foo/;+5p 2 | /foo/;+5p 3 | -------------------------------------------------------------------------------- /tests/integration/address-range-semicolon-print/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/address-range-semicolon-print/testdata/input-file: -------------------------------------------------------------------------------- 1 | this line contains the word 'foo' 2 | and aftr this line there are 3 | 5 more lines 4 | which can be printed 5 | by an ed range 6 | 7 | however, this line also has the word 'foo' 8 | but no 5 lines after it, hence causing an error when selected as a range start. 9 | -------------------------------------------------------------------------------- /tests/integration/address-ranges/cmds: -------------------------------------------------------------------------------- 1 | /^## Foobar/,/^##/p 2 | /^## Foobar/;/^##/p 3 | -------------------------------------------------------------------------------- /tests/integration/address-ranges/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/address-ranges/testdata/input-file: -------------------------------------------------------------------------------- 1 | The file starts here. 2 | 3 | ## Foobar 4 | 5 | Bla 6 | bla 7 | bla 8 | 9 | ## Foobaz 10 | 11 | Foo bar bla. 12 | 13 | ## Test 14 | 15 | test 123 16 | 456. 17 | -------------------------------------------------------------------------------- /tests/integration/address-regex-syntax-error/cmds: -------------------------------------------------------------------------------- 1 | /\{foo,foo\}/p 2 | -------------------------------------------------------------------------------- /tests/integration/address-regex-syntax-error/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/address-regex-syntax-error/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/append-and-list/cmds: -------------------------------------------------------------------------------- 1 | al 2 | τ 3 | . 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/append-and-list/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/append-and-list/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/append-and-n/cmds: -------------------------------------------------------------------------------- 1 | an 2 | baz 3 | . 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/append-and-n/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/append-and-n/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/append-and-print/cmds: -------------------------------------------------------------------------------- 1 | ap 2 | baz 3 | . 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/append-and-print/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/append-and-print/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/append-at-beginning/cmds: -------------------------------------------------------------------------------- 1 | 0a 2 | 123 3 | . 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/append-at-beginning/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/append-at-beginning/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/append-at-end/cmds: -------------------------------------------------------------------------------- 1 | a 2 | 123 3 | . 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/append-at-end/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/append-at-end/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/append-between/cmds: -------------------------------------------------------------------------------- 1 | 0+1a 2 | --- 3 | . 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/append-between/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/append-between/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | baz 3 | -------------------------------------------------------------------------------- /tests/integration/append-empty-not-modified/cmds: -------------------------------------------------------------------------------- 1 | a 2 | . 3 | q 4 | -------------------------------------------------------------------------------- /tests/integration/append-line-update/cmds: -------------------------------------------------------------------------------- 1 | 2a 2 | 3 3 | . 4 | a 5 | 4 6 | . 7 | w 8 | -------------------------------------------------------------------------------- /tests/integration/append-line-update/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/append-line-update/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 5 4 | 6 5 | -------------------------------------------------------------------------------- /tests/integration/append-newlines/cmds: -------------------------------------------------------------------------------- 1 | a 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | foo 10 | 11 | 12 | 13 | 14 | 15 | . 16 | -------------------------------------------------------------------------------- /tests/integration/append-nth/cmds: -------------------------------------------------------------------------------- 1 | 2a 2 | foobar 3 | . 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/append-nth/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/append-nth/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/change-and-n/cmds: -------------------------------------------------------------------------------- 1 | 3,$cn 2 | test 3 | . 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/change-and-n/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/change-and-n/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/change-default/cmds: -------------------------------------------------------------------------------- 1 | c 2 | foobar 3 | . 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/change-default/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/change-default/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/integration/change-delete-everything/cmds: -------------------------------------------------------------------------------- 1 | 1,$c 2 | . 3 | w 4 | -------------------------------------------------------------------------------- /tests/integration/change-delete-everything/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/change-delete-everything/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/change-insert-more-lines/cmds: -------------------------------------------------------------------------------- 1 | c 2 | foo 3 | bar 4 | . 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/change-insert-more-lines/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/change-insert-more-lines/testdata/input-file: -------------------------------------------------------------------------------- 1 | 123 2 | -------------------------------------------------------------------------------- /tests/integration/change-line-update/cmds: -------------------------------------------------------------------------------- 1 | 3,c 2 | 3 3 | . 4 | a 5 | 4 6 | . 7 | w 8 | -------------------------------------------------------------------------------- /tests/integration/change-line-update/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/change-line-update/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 9 4 | 5 5 | -------------------------------------------------------------------------------- /tests/integration/change-no-input/cmds: -------------------------------------------------------------------------------- 1 | H 2 | 1,3c 3 | . 4 | a 5 | end 6 | . 7 | w 8 | -------------------------------------------------------------------------------- /tests/integration/change-no-input/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/change-no-input/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/command-mode-eof-modified/cmds: -------------------------------------------------------------------------------- 1 | a 2 | foobar 3 | . 4 | -------------------------------------------------------------------------------- /tests/integration/command-mode-eof/cmds: -------------------------------------------------------------------------------- 1 | a 2 | . 3 | -------------------------------------------------------------------------------- /tests/integration/confirm-quit-when-no-tty/cmds: -------------------------------------------------------------------------------- 1 | a 2 | foo 3 | . 4 | q 5 | .= 6 | -------------------------------------------------------------------------------- /tests/integration/confirm-quit-when-no-tty/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/confirm-quit-when-no-tty/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/integration/copy-to-end/cmds: -------------------------------------------------------------------------------- 1 | 1,1t$ 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/copy-to-end/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/copy-to-end/testdata/input-file: -------------------------------------------------------------------------------- 1 | --- 2 | 1 3 | 2 4 | 3 5 | -------------------------------------------------------------------------------- /tests/integration/copy-to-start/cmds: -------------------------------------------------------------------------------- 1 | $,$t 0 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/copy-to-start/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/copy-to-start/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | --- 5 | -------------------------------------------------------------------------------- /tests/integration/copy-with-offset/cmds: -------------------------------------------------------------------------------- 1 | 1,1t/2/+1 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/copy-with-offset/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/copy-with-offset/testdata/input-file: -------------------------------------------------------------------------------- 1 | --- 2 | 1 3 | 2 4 | +++ 5 | 3 6 | -------------------------------------------------------------------------------- /tests/integration/delete-and-append/cmds: -------------------------------------------------------------------------------- 1 | 1,2d 2 | a 3 | foo 4 | bar 5 | . 6 | w 7 | -------------------------------------------------------------------------------- /tests/integration/delete-and-append/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/delete-and-append/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 6 | -------------------------------------------------------------------------------- /tests/integration/delete-entire-buffer/cmds: -------------------------------------------------------------------------------- 1 | d 2 | a 3 | foobar 4 | . 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/delete-entire-buffer/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/delete-entire-buffer/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/integration/delete-last-line/cmds: -------------------------------------------------------------------------------- 1 | 3,3d 2 | a 3 | - 4 | . 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/delete-last-line/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/delete-last-line/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/delete-partial/cmds: -------------------------------------------------------------------------------- 1 | 1,2d 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/delete-partial/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/delete-partial/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 6 | -------------------------------------------------------------------------------- /tests/integration/delete-single-addr/cmds: -------------------------------------------------------------------------------- 1 | 2d 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/delete-single-addr/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/delete-single-addr/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/discard-first-addr/cmds: -------------------------------------------------------------------------------- 1 | 1;/stdout/ 2 | -------------------------------------------------------------------------------- /tests/integration/discard-first-addr/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/discard-first-addr/testdata/input-file: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE LambdaCase #-} 2 | import System.IO (hFlush, hPutStrLn, stdout) 3 | -------------------------------------------------------------------------------- /tests/integration/edit-confirm/cmds: -------------------------------------------------------------------------------- 1 | a 2 | fooanerdinaerwrtine iaredn daeur 3 | . 4 | e testdata/second 5 | -------------------------------------------------------------------------------- /tests/integration/edit-confirm/opts: -------------------------------------------------------------------------------- 1 | testdata/first 2 | -------------------------------------------------------------------------------- /tests/integration/edit-confirm/testdata/first: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/edit-confirm/testdata/second: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /tests/integration/edit-custom-file/cmds: -------------------------------------------------------------------------------- 1 | E testdata/second 2 | 1,$p 3 | -------------------------------------------------------------------------------- /tests/integration/edit-custom-file/opts: -------------------------------------------------------------------------------- 1 | testdata/first 2 | -------------------------------------------------------------------------------- /tests/integration/edit-custom-file/testdata/first: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/edit-custom-file/testdata/second: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /tests/integration/edit-default/cmds: -------------------------------------------------------------------------------- 1 | E testdata/input-file 2 | E 3 | -------------------------------------------------------------------------------- /tests/integration/edit-default/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/edit-marks-discarded/cmds: -------------------------------------------------------------------------------- 1 | ka 2 | 'a,'ap 3 | E testdata/second 4 | 'ap 5 | -------------------------------------------------------------------------------- /tests/integration/edit-marks-discarded/opts: -------------------------------------------------------------------------------- 1 | testdata/first 2 | -------------------------------------------------------------------------------- /tests/integration/edit-marks-discarded/testdata/first: -------------------------------------------------------------------------------- 1 | foobar 2 | barfoo 3 | -------------------------------------------------------------------------------- /tests/integration/edit-marks-discarded/testdata/second: -------------------------------------------------------------------------------- 1 | first line 2 | second line 3 | -------------------------------------------------------------------------------- /tests/integration/edit-twice/cmds: -------------------------------------------------------------------------------- 1 | e testdata/first 2 | a 3 | first edit 4 | . 5 | w 6 | e testdata/second 7 | a 8 | second edit 9 | . 10 | w 11 | -------------------------------------------------------------------------------- /tests/integration/edit-twice/testdata/first: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/edit-twice/testdata/second: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /tests/integration/edit-unset-modified/cmds: -------------------------------------------------------------------------------- 1 | a 2 | foo 3 | . 4 | E testdata/second 5 | q 6 | -------------------------------------------------------------------------------- /tests/integration/edit-unset-modified/opts: -------------------------------------------------------------------------------- 1 | testdata/first 2 | -------------------------------------------------------------------------------- /tests/integration/edit-unset-modified/testdata/first: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/integration/edit-unset-modified/testdata/second: -------------------------------------------------------------------------------- 1 | bar 2 | -------------------------------------------------------------------------------- /tests/integration/edit-with-command/cmds: -------------------------------------------------------------------------------- 1 | e !printf "foo\nbar\nfoobar\n" 2 | -------------------------------------------------------------------------------- /tests/integration/filename-line-unchanged/cmds: -------------------------------------------------------------------------------- 1 | a 2 | 4 3 | . 4 | f testdata/second 5 | a 6 | 6 7 | . 8 | w 9 | -------------------------------------------------------------------------------- /tests/integration/filename-line-unchanged/opts: -------------------------------------------------------------------------------- 1 | testdata/first 2 | -------------------------------------------------------------------------------- /tests/integration/filename-line-unchanged/testdata/first: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/filename-line-unchanged/testdata/second: -------------------------------------------------------------------------------- 1 | 5 2 | -------------------------------------------------------------------------------- /tests/integration/filename-new-file/cmds: -------------------------------------------------------------------------------- 1 | f testdata/second 2 | -------------------------------------------------------------------------------- /tests/integration/filename-new-file/opts: -------------------------------------------------------------------------------- 1 | testdata/first 2 | -------------------------------------------------------------------------------- /tests/integration/filename-new-file/testdata/first: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/filename-new-file/testdata/second: -------------------------------------------------------------------------------- 1 | . 2 | -------------------------------------------------------------------------------- /tests/integration/filename-same-file/cmds: -------------------------------------------------------------------------------- 1 | f 2 | -------------------------------------------------------------------------------- /tests/integration/filename-same-file/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/filename-same-file/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobar 2 | -------------------------------------------------------------------------------- /tests/integration/filename-shell-command/cmds: -------------------------------------------------------------------------------- 1 | f !echo foobar 2 | -------------------------------------------------------------------------------- /tests/integration/filename-silent/cmds: -------------------------------------------------------------------------------- 1 | f testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/filename-silent/opts: -------------------------------------------------------------------------------- 1 | -s 2 | -------------------------------------------------------------------------------- /tests/integration/filename-silent/testdata/input-file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmeum/edward/3d7b0ff9d425a6eb39397eb9cab3df70b83eaab8/tests/integration/filename-silent/testdata/input-file -------------------------------------------------------------------------------- /tests/integration/forward-backward-current-matches/cmds: -------------------------------------------------------------------------------- 1 | 2p 2 | /matches/p 3 | 2p 4 | ?matches?p 5 | -------------------------------------------------------------------------------- /tests/integration/forward-backward-current-matches/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/forward-backward-current-matches/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:no match 2 | 2:this line matches 3 | 3:this line matches too 4 | -------------------------------------------------------------------------------- /tests/integration/global-append-omit-terminator/cmds: -------------------------------------------------------------------------------- 1 | g/foo/a\ 2 | this line was inserted 3 | .= 4 | g/foo/a\ 5 | also inserted this line\ 6 | and this one too 7 | w 8 | -------------------------------------------------------------------------------- /tests/integration/global-append-omit-terminator/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-append-omit-terminator/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/global-append/cmds: -------------------------------------------------------------------------------- 1 | g/foo/a\ 2 | append1 \ 3 | append2 \ 4 | . 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/global-append/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-append/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:foo 2 | 2:bar 3 | 3:foo 4 | -------------------------------------------------------------------------------- /tests/integration/global-change/cmds: -------------------------------------------------------------------------------- 1 | g/foo/c\ 2 | change1 \ 3 | change2 \ 4 | . 5 | .= 6 | w 7 | -------------------------------------------------------------------------------- /tests/integration/global-change/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-change/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:foo 2 | 2:bar 3 | 3:foobar 4 | -------------------------------------------------------------------------------- /tests/integration/global-delete-everything/cmds: -------------------------------------------------------------------------------- 1 | g/foo/1,$d 2 | .= 3 | w 4 | -------------------------------------------------------------------------------- /tests/integration/global-delete-everything/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-delete-everything/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:foo 2 | 2:bar 3 | 3:foobar 4 | -------------------------------------------------------------------------------- /tests/integration/global-delim/cmds: -------------------------------------------------------------------------------- 1 | 1,$g|foo|p 2 | -------------------------------------------------------------------------------- /tests/integration/global-delim/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-delim/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:test 2 | 2:foo 3 | 3:test 4 | 4:foobar 5 | 5:blaba foo blabla 6 | -------------------------------------------------------------------------------- /tests/integration/global-delimiter-omitted-substitute/cmds: -------------------------------------------------------------------------------- 1 | g/x/s/x/y 2 | -------------------------------------------------------------------------------- /tests/integration/global-delimiter-omitted-substitute/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-delimiter-omitted-substitute/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bxx 3 | -------------------------------------------------------------------------------- /tests/integration/global-empty/cmds: -------------------------------------------------------------------------------- 1 | H 2 | 1,$g/foo/ 3 | -------------------------------------------------------------------------------- /tests/integration/global-empty/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-empty/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:test 2 | 2:foo 3 | -------------------------------------------------------------------------------- /tests/integration/global-esc-delim/cmds: -------------------------------------------------------------------------------- 1 | 1,$g/f\//p 2 | -------------------------------------------------------------------------------- /tests/integration/global-esc-delim/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-esc-delim/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:f// 2 | 2:foo 3 | 3:f/ 4 | -------------------------------------------------------------------------------- /tests/integration/global-insert/cmds: -------------------------------------------------------------------------------- 1 | g/foo/i\ 2 | insert1 \ 3 | insert2 \ 4 | . 5 | .= 6 | w 7 | -------------------------------------------------------------------------------- /tests/integration/global-insert/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-insert/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:foo 2 | 2:bar 3 | 3:foobar 4 | -------------------------------------------------------------------------------- /tests/integration/global-multiline/cmds: -------------------------------------------------------------------------------- 1 | H 2 | g|foo|d\ 3 | 1s/^/test/\ 4 | p 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/global-multiline/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-multiline/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:foobar 2 | 2:bar 3 | 3:baz 4 | -------------------------------------------------------------------------------- /tests/integration/global-multiple-commands/cmds: -------------------------------------------------------------------------------- 1 | g/foo/c\ 2 | change1\ 3 | . \ 4 | a\ 5 | append1\ 6 | .\ 7 | 1d 8 | .= 9 | w 10 | -------------------------------------------------------------------------------- /tests/integration/global-multiple-commands/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-multiple-commands/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:foo 2 | 2:bar 3 | 3:foobar 4 | -------------------------------------------------------------------------------- /tests/integration/global-no-match/cmds: -------------------------------------------------------------------------------- 1 | .= 2 | /foo/g 3 | .= 4 | -------------------------------------------------------------------------------- /tests/integration/global-no-match/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-no-match/testdata/input-file: -------------------------------------------------------------------------------- 1 | bar 2 | baz 3 | 123 4 | -------------------------------------------------------------------------------- /tests/integration/global-no-terminating-dot/cmds: -------------------------------------------------------------------------------- 1 | g/foobar/a\ 2 | no\ 3 | terminating\ 4 | period\ 5 | character\ 6 | . 7 | .= 8 | w 9 | -------------------------------------------------------------------------------- /tests/integration/global-no-terminating-dot/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-no-terminating-dot/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobar 2 | -------------------------------------------------------------------------------- /tests/integration/global-non-matched/cmds: -------------------------------------------------------------------------------- 1 | v/foo/ 2 | .= 3 | v/foo/p 4 | .= 5 | v/foo/s|^[a-z]*|foo| 6 | .= 7 | v/foo/p 8 | .= 9 | 1,$p 10 | Q 11 | -------------------------------------------------------------------------------- /tests/integration/global-non-matched/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-non-matched/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/global-null-re/cmds: -------------------------------------------------------------------------------- 1 | 1,$g/foo/p 2 | 1,$g//p 3 | .= 4 | -------------------------------------------------------------------------------- /tests/integration/global-null-re/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-null-re/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:test 2 | 2:foo 3 | 3:test 4 | -------------------------------------------------------------------------------- /tests/integration/global-print/cmds: -------------------------------------------------------------------------------- 1 | 1,$g/foo/p 2 | .= 3 | -------------------------------------------------------------------------------- /tests/integration/global-print/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-print/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:test 2 | 2:foo 3 | 3:test 4 | 4:foobar 5 | 5:blaba foo blabla 6 | -------------------------------------------------------------------------------- /tests/integration/global-regex-syntax-error/cmds: -------------------------------------------------------------------------------- 1 | g/[/p 2 | -------------------------------------------------------------------------------- /tests/integration/global-regex-syntax-error/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-regex-syntax-error/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobar 2 | -------------------------------------------------------------------------------- /tests/integration/global-substitute-nomatch1/cmds: -------------------------------------------------------------------------------- 1 | g/baz/p\ 2 | s/baz/replaced/ 3 | .= 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/global-substitute-nomatch1/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-substitute-nomatch1/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/global-substitute-nomatch2/cmds: -------------------------------------------------------------------------------- 1 | g/baz/p\ 2 | s/doesn't match any line/replaced/ 3 | .= 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/global-substitute-nomatch2/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/global-substitute-nomatch2/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/input-mode-eof/cmds: -------------------------------------------------------------------------------- 1 | a 2 | foo 3 | bar 4 | baz 5 | -------------------------------------------------------------------------------- /tests/integration/insert-before/cmds: -------------------------------------------------------------------------------- 1 | 2i 2 | bla 3 | . 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/insert-before/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/insert-before/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/insert-zero/cmds: -------------------------------------------------------------------------------- 1 | 0 i 2 | 123 3 | . 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/insert-zero/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/insert-zero/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/interactive-nested-global/cmds: -------------------------------------------------------------------------------- 1 | G/foo/ 2 | g/foo/ 3 | -------------------------------------------------------------------------------- /tests/integration/interactive-nested-global/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/interactive-nested-global/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/interactive-no-previous/cmds: -------------------------------------------------------------------------------- 1 | G/foo/ 2 | & 3 | -------------------------------------------------------------------------------- /tests/integration/interactive-no-previous/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/interactive-no-previous/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/interactive-null-command/cmds: -------------------------------------------------------------------------------- 1 | H 2 | G/foo/ 3 | s/foo/test1/ 4 | 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/interactive-null-command/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/interactive-null-command/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo1 2 | bar 3 | foobar2 4 | -------------------------------------------------------------------------------- /tests/integration/interactive-null-repeat/cmds: -------------------------------------------------------------------------------- 1 | G/foo/ 2 | s/foo/test/ 3 | 4 | & 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/interactive-null-repeat/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/interactive-null-repeat/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo1 2 | bar1 3 | foo2 4 | bar2 5 | foo3 6 | -------------------------------------------------------------------------------- /tests/integration/interactive-previous/cmds: -------------------------------------------------------------------------------- 1 | G/foo/ 2 | d 3 | & 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/interactive-previous/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/interactive-previous/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo1 2 | bar 3 | foobar2 4 | -------------------------------------------------------------------------------- /tests/integration/interactive-repeat/cmds: -------------------------------------------------------------------------------- 1 | G/^f/ 2 | s/foo/test/ 3 | & 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/interactive-repeat/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/interactive-repeat/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo1 2 | 1234 3 | foo2 4 | -------------------------------------------------------------------------------- /tests/integration/interactive-unmatched/cmds: -------------------------------------------------------------------------------- 1 | H 2 | V/foo/ 3 | d 4 | 5 | & 6 | w 7 | -------------------------------------------------------------------------------- /tests/integration/interactive-unmatched/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/interactive-unmatched/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo1 2 | bar 3 | 123 4 | foobar2 5 | 456 6 | -------------------------------------------------------------------------------- /tests/integration/interactive/cmds: -------------------------------------------------------------------------------- 1 | H 2 | G/foo/ 3 | s/foo/test1/ 4 | s/foo/test2/ 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/interactive/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/interactive/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo1 2 | bar 3 | foobar2 4 | -------------------------------------------------------------------------------- /tests/integration/invalid-range/cmds: -------------------------------------------------------------------------------- 1 | 3,1p 2 | -------------------------------------------------------------------------------- /tests/integration/invalid-range/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/invalid-range/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/join-all/cmds: -------------------------------------------------------------------------------- 1 | 1,$j 2 | .= 3 | w 4 | -------------------------------------------------------------------------------- /tests/integration/join-all/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/join-all/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/join-lines/cmds: -------------------------------------------------------------------------------- 1 | 2,3j 2 | .= 3 | w 4 | -------------------------------------------------------------------------------- /tests/integration/join-lines/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/join-lines/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | -------------------------------------------------------------------------------- /tests/integration/join-nothing/cmds: -------------------------------------------------------------------------------- 1 | 1,1j 2 | .= 3 | w 4 | -------------------------------------------------------------------------------- /tests/integration/join-nothing/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/join-nothing/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | >>> 4 | <<< 5 | -------------------------------------------------------------------------------- /tests/integration/line-number-default/cmds: -------------------------------------------------------------------------------- 1 | H 2 | = 3 | 2,3c 4 | . 5 | = 6 | w 7 | -------------------------------------------------------------------------------- /tests/integration/line-number-default/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/line-number-default/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/line-number-empty/cmds: -------------------------------------------------------------------------------- 1 | = 2 | -------------------------------------------------------------------------------- /tests/integration/line-number-empty/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/line-number-empty/testdata/input-file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmeum/edward/3d7b0ff9d425a6eb39397eb9cab3df70b83eaab8/tests/integration/line-number-empty/testdata/input-file -------------------------------------------------------------------------------- /tests/integration/line-number-zero/cmds: -------------------------------------------------------------------------------- 1 | = 2 | -------------------------------------------------------------------------------- /tests/integration/list-backslash/cmds: -------------------------------------------------------------------------------- 1 | 1,$l 2 | -------------------------------------------------------------------------------- /tests/integration/list-backslash/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/list-backslash/testdata/input-file: -------------------------------------------------------------------------------- 1 | b\ar$f\oo\ 2 | -------------------------------------------------------------------------------- /tests/integration/list-multiple-lines/cmds: -------------------------------------------------------------------------------- 1 | 1,$l 2 | -------------------------------------------------------------------------------- /tests/integration/list-multiple-lines/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/list-multiple-lines/testdata/input-file: -------------------------------------------------------------------------------- 1 | ιoι 2 | bσr 3 | -------------------------------------------------------------------------------- /tests/integration/list-pad-with-zeros/cmds: -------------------------------------------------------------------------------- 1 | 1,$l 2 | -------------------------------------------------------------------------------- /tests/integration/list-pad-with-zeros/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/list-pad-with-zeros/testdata/input-file: -------------------------------------------------------------------------------- 1 |  2 | -------------------------------------------------------------------------------- /tests/integration/list-unicode/cmds: -------------------------------------------------------------------------------- 1 | 1,$l 2 | -------------------------------------------------------------------------------- /tests/integration/list-unicode/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/list-unicode/testdata/input-file: -------------------------------------------------------------------------------- 1 | λ 2 | -------------------------------------------------------------------------------- /tests/integration/mark-and-delete/cmds: -------------------------------------------------------------------------------- 1 | 2kx 2 | 'xp 3 | 'xd 4 | 'xp 5 | Q 6 | -------------------------------------------------------------------------------- /tests/integration/mark-and-delete/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/mark-and-delete/testdata/input-file: -------------------------------------------------------------------------------- 1 | first line 2 | second line 3 | third line 4 | -------------------------------------------------------------------------------- /tests/integration/mark-and-move/cmds: -------------------------------------------------------------------------------- 1 | 2kx 2 | 'xp 3 | 2m$ 4 | 'xp 5 | Q 6 | -------------------------------------------------------------------------------- /tests/integration/mark-and-move/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/mark-and-move/testdata/input-file: -------------------------------------------------------------------------------- 1 | first line 2 | second line 3 | third line 4 | -------------------------------------------------------------------------------- /tests/integration/mark-empty-buffer/cmds: -------------------------------------------------------------------------------- 1 | 2kx 2 | -------------------------------------------------------------------------------- /tests/integration/mark-first-line/cmds: -------------------------------------------------------------------------------- 1 | H 2 | = 3 | a 4 | 5 5 | 6 6 | . 7 | 1kf 8 | 'fi 9 | 1 10 | . 11 | w 12 | -------------------------------------------------------------------------------- /tests/integration/mark-first-line/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/mark-first-line/testdata/input-file: -------------------------------------------------------------------------------- 1 | 2 2 | 3 3 | 4 4 | 5 5 | 6 6 | 5 7 | 6 8 | -------------------------------------------------------------------------------- /tests/integration/mark-invalid/cmds: -------------------------------------------------------------------------------- 1 | 1kfoobar 2 | -------------------------------------------------------------------------------- /tests/integration/mark-invalid/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/mark-invalid/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/mark-overwrite/cmds: -------------------------------------------------------------------------------- 1 | = 2 | a 3 | 4 4 | 5 5 | 6 6 | . 7 | 1kf 8 | $kf 9 | a 10 | 7 11 | 8 12 | 9 13 | . 14 | w 15 | -------------------------------------------------------------------------------- /tests/integration/mark-overwrite/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/mark-overwrite/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/mark-zero-line/cmds: -------------------------------------------------------------------------------- 1 | a 2 | foo 3 | bar 4 | baz 5 | . 6 | 0kf 7 | -------------------------------------------------------------------------------- /tests/integration/move-after/cmds: -------------------------------------------------------------------------------- 1 | 2,3m5 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/move-after/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/move-after/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | test 5 | --- 6 | 7 | bla 8 | -------------------------------------------------------------------------------- /tests/integration/move-between/cmds: -------------------------------------------------------------------------------- 1 | 5,6m2 2 | .= 3 | w 4 | -------------------------------------------------------------------------------- /tests/integration/move-between/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/move-between/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 5 4 | 6 5 | 3 6 | 4 7 | 7 8 | 8 9 | -------------------------------------------------------------------------------- /tests/integration/move-overlapping-range/cmds: -------------------------------------------------------------------------------- 1 | 1,3m2 2 | 1,2m2 3 | -------------------------------------------------------------------------------- /tests/integration/move-overlapping-range/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/move-overlapping-range/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/move-to-end/cmds: -------------------------------------------------------------------------------- 1 | 1,1m3 2 | .= 3 | w 4 | -------------------------------------------------------------------------------- /tests/integration/move-to-end/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/move-to-end/testdata/input-file: -------------------------------------------------------------------------------- 1 | 3 2 | 1 3 | 2 4 | -------------------------------------------------------------------------------- /tests/integration/move-to-start/cmds: -------------------------------------------------------------------------------- 1 | 2,$m0 2 | .= 3 | w 4 | -------------------------------------------------------------------------------- /tests/integration/move-to-start/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/move-to-start/testdata/input-file: -------------------------------------------------------------------------------- 1 | 3 2 | 1 3 | 2 4 | -------------------------------------------------------------------------------- /tests/integration/move-update-current-on-single-line/cmds: -------------------------------------------------------------------------------- 1 | 2m3 2 | .= 3 | Q 4 | -------------------------------------------------------------------------------- /tests/integration/move-update-current-on-single-line/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/move-update-current-on-single-line/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | bla 5 | blubb 6 | -------------------------------------------------------------------------------- /tests/integration/multiple-addresses/cmds: -------------------------------------------------------------------------------- 1 | H 2 | 7,p 3 | 7,5,p 4 | 7,5,9p 5 | 7,9p 6 | 7,+p 7 | ,p 8 | ,7p 9 | ,,p 10 | ,;p 11 | 7;p 12 | 7;5;p 13 | 7;5;9p 14 | 7;5,9p 15 | 7;9p 16 | 7;+p 17 | ;p 18 | 1p 19 | ;7p 20 | ;;p 21 | ;,p 22 | -------------------------------------------------------------------------------- /tests/integration/multiple-addresses/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/multiple-addresses/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 6 | 6 7 | 7 8 | 8 9 | 9 10 | 10 11 | 11 12 | 12 13 | 13 14 | 14 15 | 15 16 | 16 17 | 17 18 | 18 19 | 19 20 | 20 21 | -------------------------------------------------------------------------------- /tests/integration/no-null-re/cmds: -------------------------------------------------------------------------------- 1 | //p 2 | -------------------------------------------------------------------------------- /tests/integration/no-null-re/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/no-null-re/testdata/input-file: -------------------------------------------------------------------------------- 1 | 123 2 | foobar 3 | 234 4 | -------------------------------------------------------------------------------- /tests/integration/nonexistend-file-read/cmds: -------------------------------------------------------------------------------- 1 | e testdata/does/not/exist 2 | -------------------------------------------------------------------------------- /tests/integration/nonexistend-file-write/cmds: -------------------------------------------------------------------------------- 1 | a 2 | write should error and therefore quit should require confirmation 3 | . 4 | w /tmp/does/not/exist 5 | q 6 | Q 7 | -------------------------------------------------------------------------------- /tests/integration/null-command-with-address/cmds: -------------------------------------------------------------------------------- 1 | 4 2 | .= 3 | -------------------------------------------------------------------------------- /tests/integration/null-command-with-address/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/null-command-with-address/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | bla 4 | baz 5 | -------------------------------------------------------------------------------- /tests/integration/null-command-with-zero-address/cmds: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /tests/integration/null-command-with-zero-address/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/null-command-with-zero-address/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /tests/integration/null-command/cmds: -------------------------------------------------------------------------------- 1 | 1,1p 2 | 3 | 4 | .= 5 | -------------------------------------------------------------------------------- /tests/integration/null-command/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/null-command/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | bla 4 | -------------------------------------------------------------------------------- /tests/integration/null-re-range/cmds: -------------------------------------------------------------------------------- 1 | /main/-1,/main/+1p 2 | g//p 3 | 1,$s//program/g 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/null-re-range/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/null-re-range/testdata/input-file: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | main_loop(void) 5 | { 6 | /* … */ 7 | } 8 | 9 | int 10 | main(void) 11 | { 12 | puts("Hello, World"); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /tests/integration/null-re/cmds: -------------------------------------------------------------------------------- 1 | /foo/p 2 | //p 3 | +1p 4 | //p 5 | +1p 6 | ??p 7 | -------------------------------------------------------------------------------- /tests/integration/null-re/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/null-re/testdata/input-file: -------------------------------------------------------------------------------- 1 | 123 2 | foobar 3 | 234 4 | -------------------------------------------------------------------------------- /tests/integration/number-change-line/cmds: -------------------------------------------------------------------------------- 1 | 2,3n 2 | .= 3 | -------------------------------------------------------------------------------- /tests/integration/number-change-line/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/number-change-line/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | bla 4 | baz 5 | -------------------------------------------------------------------------------- /tests/integration/number-default/cmds: -------------------------------------------------------------------------------- 1 | n 2 | -------------------------------------------------------------------------------- /tests/integration/number-default/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/number-default/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/number-full/cmds: -------------------------------------------------------------------------------- 1 | 1,$n 2 | -------------------------------------------------------------------------------- /tests/integration/number-full/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/number-full/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/number-partial/cmds: -------------------------------------------------------------------------------- 1 | 2,3n 2 | -------------------------------------------------------------------------------- /tests/integration/number-partial/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/number-partial/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | bla 4 | baz 5 | -------------------------------------------------------------------------------- /tests/integration/omitting-re-delimiter/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/foo/test 2 | g/bar 3 | v/bar 4 | ?test 5 | /baz 6 | w 7 | -------------------------------------------------------------------------------- /tests/integration/omitting-re-delimiter/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/omitting-re-delimiter/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/pass-shell-command-as-cmdarg/cmds: -------------------------------------------------------------------------------- 1 | 1,$p 2 | -------------------------------------------------------------------------------- /tests/integration/pass-shell-command-as-cmdarg/opts: -------------------------------------------------------------------------------- 1 | !uname|head 2 | -------------------------------------------------------------------------------- /tests/integration/prefix-print-with-print/cmds: -------------------------------------------------------------------------------- 1 | 1,$ll 2 | 1,$nn 3 | 1,$pp 4 | -------------------------------------------------------------------------------- /tests/integration/prefix-print-with-print/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/prefix-print-with-print/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/print-match-backward-multiple-matches/cmds: -------------------------------------------------------------------------------- 1 | 3p 2 | ?^foobar$?p 3 | .= 4 | -------------------------------------------------------------------------------- /tests/integration/print-match-backward-multiple-matches/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/print-match-backward-multiple-matches/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobar 2 | $ 3 | current-line 4 | $ 5 | foobar 6 | -------------------------------------------------------------------------------- /tests/integration/print-match-backward/cmds: -------------------------------------------------------------------------------- 1 | H 2 | ?foobar?p 3 | .= 4 | ?foobar?p 5 | .= 6 | -------------------------------------------------------------------------------- /tests/integration/print-match-backward/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/print-match-backward/testdata/input-file: -------------------------------------------------------------------------------- 1 | this is a testfile 2 | 3 | this line contains foobar 4 | this line contains blaoo 5 | -------------------------------------------------------------------------------- /tests/integration/print-match-forward-no-match/cmds: -------------------------------------------------------------------------------- 1 | /no match/p 2 | .= 3 | -------------------------------------------------------------------------------- /tests/integration/print-match-forward-no-match/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/print-match-forward-no-match/testdata/input-file: -------------------------------------------------------------------------------- 1 | this is a testfile 2 | 3 | this line contains foobar 4 | this line contains blaoo 5 | -------------------------------------------------------------------------------- /tests/integration/print-match-forward-wraparound/cmds: -------------------------------------------------------------------------------- 1 | /foobar/p 2 | /te[a-z][a-z]*/p 3 | -------------------------------------------------------------------------------- /tests/integration/print-match-forward-wraparound/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/print-match-forward-wraparound/testdata/input-file: -------------------------------------------------------------------------------- 1 | this is a testfile 2 | 3 | this line contains foobar 4 | this line contains blaoo 5 | -------------------------------------------------------------------------------- /tests/integration/print-match-forward/cmds: -------------------------------------------------------------------------------- 1 | /foobar/p 2 | .= 3 | /foobar/p 4 | .= 5 | -------------------------------------------------------------------------------- /tests/integration/print-match-forward/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/print-match-forward/testdata/input-file: -------------------------------------------------------------------------------- 1 | this is a testfile 2 | 3 | this line contains foobar 4 | this line contains blaoo 5 | -------------------------------------------------------------------------------- /tests/integration/print-single/cmds: -------------------------------------------------------------------------------- 1 | 2p 2 | .= 3 | Q 4 | -------------------------------------------------------------------------------- /tests/integration/print-single/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/print-single/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/print/cmds: -------------------------------------------------------------------------------- 1 | 2,3p 2 | .= 3 | -------------------------------------------------------------------------------- /tests/integration/print/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/print/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | bla 4 | baz 5 | -------------------------------------------------------------------------------- /tests/integration/quit-address/cmds: -------------------------------------------------------------------------------- 1 | 2q 2 | -------------------------------------------------------------------------------- /tests/integration/quit-address/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/quit-address/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/quit-confirmed/cmds: -------------------------------------------------------------------------------- 1 | a 2 | foobar 3 | . 4 | q 5 | q 6 | .= 7 | -------------------------------------------------------------------------------- /tests/integration/quit-confirmed/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/quit-confirmed/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/integration/quit-file-modified/cmds: -------------------------------------------------------------------------------- 1 | a 2 | foobar 3 | . 4 | q 5 | -------------------------------------------------------------------------------- /tests/integration/quit-file-modified/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/quit-file-modified/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/integration/quit-no-file/cmds: -------------------------------------------------------------------------------- 1 | q 2 | -------------------------------------------------------------------------------- /tests/integration/quit-no-file/opts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmeum/edward/3d7b0ff9d425a6eb39397eb9cab3df70b83eaab8/tests/integration/quit-no-file/opts -------------------------------------------------------------------------------- /tests/integration/quit-not-modified/cmds: -------------------------------------------------------------------------------- 1 | q 2 | -------------------------------------------------------------------------------- /tests/integration/quit-not-modified/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/quit-not-modified/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | bla 4 | baz 5 | -------------------------------------------------------------------------------- /tests/integration/quit-without-checking/cmds: -------------------------------------------------------------------------------- 1 | a 2 | foo 3 | . 4 | Q 5 | -------------------------------------------------------------------------------- /tests/integration/read-command-empty/cmds: -------------------------------------------------------------------------------- 1 | r !true 2 | -------------------------------------------------------------------------------- /tests/integration/read-command-twice/cmds: -------------------------------------------------------------------------------- 1 | r !printf "foo\n12345\n" 2 | r !echo "test test test" 3 | Q 4 | -------------------------------------------------------------------------------- /tests/integration/read-dont-remember-command/cmds: -------------------------------------------------------------------------------- 1 | read !printf "λ\nfoo\nbar\nbaz\nλ\n" 2 | f 3 | -------------------------------------------------------------------------------- /tests/integration/read-from-command/cmds: -------------------------------------------------------------------------------- 1 | read !printf "λ\nfoo\nbar\nbaz\nλ\n" 2 | 1,$p 3 | -------------------------------------------------------------------------------- /tests/integration/read-no-space/cmds: -------------------------------------------------------------------------------- 1 | rtestdata/in 2 | -------------------------------------------------------------------------------- /tests/integration/read-no-space/testdata/in: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/read-set-default/cmds: -------------------------------------------------------------------------------- 1 | r testdata/input-file 2 | $a 3 | foobar 4 | . 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/read-set-default/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/read-twice/cmds: -------------------------------------------------------------------------------- 1 | r testdata/in 2 | r testdata/in 3 | w out 4 | -------------------------------------------------------------------------------- /tests/integration/read-twice/testdata/in: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/read-write-no-file/cmds: -------------------------------------------------------------------------------- 1 | r 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/read-write-no-file/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/read-write-no-file/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/regex-empty-file/cmds: -------------------------------------------------------------------------------- 1 | /foo/p 2 | -------------------------------------------------------------------------------- /tests/integration/regex-empty-file/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/regex-empty-file/testdata/input-file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmeum/edward/3d7b0ff9d425a6eb39397eb9cab3df70b83eaab8/tests/integration/regex-empty-file/testdata/input-file -------------------------------------------------------------------------------- /tests/integration/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd "$(dirname "$0")" 4 | 5 | abort() { 6 | printf "${1}\n" 1>&2 7 | exit 1 8 | } 9 | 10 | run_editor() { 11 | [ $# -eq 4 ] || exit 1 12 | cmd="${1}" 13 | cwd="${2}" 14 | dat="${3}" 15 | opt="${4}" 16 | 17 | mkdir "${cwd}" 18 | [ -d "${dat}" ] && cp -r "${dat}" "${cwd}" 19 | cd "${cwd}" 20 | 21 | if [ -s "${opt}" ]; then 22 | set -- $(cat "${opt}") 23 | "${cmd}" $@ 2>/dev/null 24 | else 25 | "${cmd}" 2>/dev/null 26 | fi 27 | 28 | cd - >/dev/null 29 | unset cmd cwd dat opt 30 | } 31 | 32 | EDWARD="${EDWARD:-$(pwd)/../../bin/edward}" 33 | [ -x "${EDWARD}" ] || \ 34 | abort "Couldn't find edward executable '${EDWARD}'." 35 | 36 | REF_IMPL="$(command -v ed)" 37 | [ -x "${REF_IMPL}" ] || \ 38 | abort "Reference implementation not found." 39 | 40 | TESTDIR="/tmp/edward-test" 41 | TESTCWD="${TESTDIR}/cwd" 42 | EXPECTED="${TESTDIR}/expected" 43 | ACTUAL="${TESTDIR}/actual" 44 | 45 | mkdir -p "${TESTDIR}" 46 | trap "rm -rf '${TESTDIR}'" INT EXIT 47 | 48 | for test in *; do 49 | [ -d "${test}" ] || continue 50 | 51 | name="${test##*/}" 52 | printf "Running test case '%s': " "${name}" 53 | 54 | cmds="$(pwd)/${test}/cmds" 55 | opts="$(pwd)/${test}/opts" 56 | 57 | run_editor "${REF_IMPL}" "${TESTCWD}.expected" "${test}/testdata" "${opts}" \ 58 | > "${EXPECTED}" < "${cmds}" 59 | 60 | run_editor "${EDWARD}" "${TESTCWD}.actual" "${test}/testdata" "${opts}" \ 61 | > "${ACTUAL}" < "${cmds}" 62 | 63 | diff=$(diff -ur "${TESTCWD}.expected" "${TESTCWD}.actual") 64 | if [ $? -ne 0 ]; then 65 | printf "FAIL: Modified files differ.\n\n" 66 | printf "%s\n" "${diff}" 67 | exit 1 68 | fi 69 | 70 | diff=$(diff -u "${EXPECTED}" "${ACTUAL}") 71 | if [ $? -ne 0 ]; then 72 | printf "FAIL: Standard output didn't match.\n\n" 73 | printf "%s\n" "${diff}" 74 | exit 1 75 | fi 76 | 77 | printf "OK.\n" 78 | rm -rf "${TESTCWD}.actual" "${TESTCWD}.expected" 79 | done 80 | -------------------------------------------------------------------------------- /tests/integration/shell-escape-filename/cmds: -------------------------------------------------------------------------------- 1 | !echo foo \% bar 2 | -------------------------------------------------------------------------------- /tests/integration/shell-filename-multiple/cmds: -------------------------------------------------------------------------------- 1 | !echo current filename is % 2 | e testdata/second-file 3 | !echo filename is % and % still 4 | -------------------------------------------------------------------------------- /tests/integration/shell-filename-multiple/opts: -------------------------------------------------------------------------------- 1 | testdata/first-file 2 | -------------------------------------------------------------------------------- /tests/integration/shell-filename-multiple/testdata/first-file: -------------------------------------------------------------------------------- 1 | some text 2 | -------------------------------------------------------------------------------- /tests/integration/shell-filename-multiple/testdata/second-file: -------------------------------------------------------------------------------- 1 | this is the second file 2 | -------------------------------------------------------------------------------- /tests/integration/shell-filename/cmds: -------------------------------------------------------------------------------- 1 | !echo filename: % 2 | -------------------------------------------------------------------------------- /tests/integration/shell-filename/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/shell-filename/testdata/input-file: -------------------------------------------------------------------------------- 1 | some text 2 | -------------------------------------------------------------------------------- /tests/integration/shell-no-filename/cmds: -------------------------------------------------------------------------------- 1 | !echo % 2 | -------------------------------------------------------------------------------- /tests/integration/shell-no-previous/cmds: -------------------------------------------------------------------------------- 1 | !! 2 | -------------------------------------------------------------------------------- /tests/integration/shell-previous-append/cmds: -------------------------------------------------------------------------------- 1 | !echo foo bar baz 2 | !! and the filename is % 3 | -------------------------------------------------------------------------------- /tests/integration/shell-previous-append/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/shell-previous-append/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobar 2 | -------------------------------------------------------------------------------- /tests/integration/shell-previous-with-filename/cmds: -------------------------------------------------------------------------------- 1 | !echo \%\% filename = % \%\% 2 | !! 3 | -------------------------------------------------------------------------------- /tests/integration/shell-previous/cmds: -------------------------------------------------------------------------------- 1 | !printf "1\n2\n3\n" 2 | !! 3 | -------------------------------------------------------------------------------- /tests/integration/silent-mode/cmds: -------------------------------------------------------------------------------- 1 | E testdata/first-file 2 | a 3 | foo 4 | . 5 | w 6 | e testdata/second-file 7 | r testdata/first-file 8 | w 9 | !echo % 10 | -------------------------------------------------------------------------------- /tests/integration/silent-mode/opts: -------------------------------------------------------------------------------- 1 | -s 2 | -------------------------------------------------------------------------------- /tests/integration/silent-mode/testdata/first-file: -------------------------------------------------------------------------------- 1 | first 2 | -------------------------------------------------------------------------------- /tests/integration/silent-mode/testdata/second-file: -------------------------------------------------------------------------------- 1 | second 2 | -------------------------------------------------------------------------------- /tests/integration/special-addresses/cmds: -------------------------------------------------------------------------------- 1 | H 2 | 1p 3 | +++ 4 | /foo/- 5 | -2 6 | 3 ---- 2 7 | 1 2 3 8 | -------------------------------------------------------------------------------- /tests/integration/special-addresses/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/special-addresses/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:bar 2 | 2:blbababab 3 | 3:bazbababa 4 | 4:foo 5 | 5:testtesttest 6 | 6:rienradenrunaedt 7 | 7:duarenduane 8 | -------------------------------------------------------------------------------- /tests/integration/substitute-and-number/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/foo/test/gn 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-and-number/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-and-number/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:foobarfoo 2 | 2: 3 | 3:foobarfoo 4 | 4: 5 | -------------------------------------------------------------------------------- /tests/integration/substitute-and-print/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/foo/test/gp 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-and-print/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-and-print/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:foobarfoo 2 | 2:foobarfoo 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-append/cmds: -------------------------------------------------------------------------------- 1 | H 2 | s/foo/&bar/ 3 | w 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-append/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-append/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-backreference/cmds: -------------------------------------------------------------------------------- 1 | H 2 | s/\([a-z]\)oo/\1ar/ 3 | w 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-backreference/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-backreference/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-change-line/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/foo/test/ 2 | .= 3 | Q 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-change-line/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-change-line/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobarfoo 2 | 123 3 | foobarfoo 4 | 345 5 | -------------------------------------------------------------------------------- /tests/integration/substitute-delimiter-escaped/cmds: -------------------------------------------------------------------------------- 1 | 1|foo/bar|123\|345| 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-delimiter-escaped/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-delimiter-escaped/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo/bar 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-delimiter/cmds: -------------------------------------------------------------------------------- 1 | 1|foo/bar|123/345| 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-delimiter/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-delimiter/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo/bar 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-differ-matched-twice/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/T[a-z]*/T.&/g 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-differ-matched-twice/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-differ-matched-twice/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo : Text -> Testing 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-empty-replace/cmds: -------------------------------------------------------------------------------- 1 | 2s/bar// 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-empty-replace/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-empty-replace/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-empty-submatch/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/[a-z ][a-z ]* '\(.*\)'.*/matched: '\1'/ 2 | 1,$p 3 | Q 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-empty-submatch/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-empty-submatch/testdata/input-file: -------------------------------------------------------------------------------- 1 | first example text 'see figure 1' 2 | second example text '' 3 | third example text '' foo bar 4 | last example text 'something' blabab 5 | -------------------------------------------------------------------------------- /tests/integration/substitute-first/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/foo/test/ 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-first/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-first/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobarfoo 2 | foobarfoo 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-global/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/foo/test/g 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-global/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-global/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobarfoo 2 | foobarfoo 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-insert-multiple-newlines/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/

]*>\([^<][^<]*\)<\/h2>$/\ 2 | === \1\ 3 | \ 4 | 5 | w 6 | q 7 | -------------------------------------------------------------------------------- /tests/integration/substitute-insert-multiple-newlines/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-insert-multiple-newlines/testdata/input-file: -------------------------------------------------------------------------------- 1 |

Status

2 | This SRFI is currently in final status. 3 |

Abstract

4 | A flexvector, also known as a dynamic array or an arraylist 5 | -------------------------------------------------------------------------------- /tests/integration/substitute-invalid-backref/cmds: -------------------------------------------------------------------------------- 1 | 1s/foo/\1/ 2 | 2s/\(bar\)/\2"\1"\3/ 3 | 3s/\(baz\)/'\1'/ 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/substitute-invalid-backref/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-invalid-backref/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-mark-touched/cmds: -------------------------------------------------------------------------------- 1 | 2kf 2 | 1,$s/bar/the line containing the mark has been modified, the mark is now invalid/ 3 | 'fp 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-mark-touched/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-mark-touched/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-mark-untouched/cmds: -------------------------------------------------------------------------------- 1 | 2kf 2 | 1,$s/f/z/ 3 | 'fp 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-mark-untouched/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-mark-untouched/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-matched-twice/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/Text/T.&/g 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-matched-twice/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-matched-twice/testdata/input-file: -------------------------------------------------------------------------------- 1 | trim :: T.Text -> T.Text 2 | trim = rtrim . ltrim 3 | where 4 | ltrim :: T.Text -> T.Text 5 | ltrim = T.dropWhile isSpace 6 | -------------------------------------------------------------------------------- /tests/integration/substitute-missing-pattern/cmds: -------------------------------------------------------------------------------- 1 | s/sample 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-missing-pattern/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-missing-pattern/testdata/input-file: -------------------------------------------------------------------------------- 1 | sample input 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-modified-but-same/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/foo/foo/n 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-modified-but-same/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-modified-but-same/testdata/input-file: -------------------------------------------------------------------------------- 1 | bar 2 | barfootest 3 | foo 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-multiline-print/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/foo/foo\ 2 | inserted line/p 3 | .= 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/substitute-multiline-print/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-multiline-print/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-multiline/cmds: -------------------------------------------------------------------------------- 1 | s/foo\(.*\)/foo \ 2 | \1/ 3 | .= 4 | w 5 | -------------------------------------------------------------------------------- /tests/integration/substitute-multiline/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-multiline/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobar 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-no-match/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/no match/test/g 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-no-match/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-no-match/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobarfoo 2 | foobarfoo 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-no-prev-replace/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/foo/%/g 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-no-prev-replace/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-no-prev-replace/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobarfoo 2 | foobarfoo 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-non-participating-submatch/cmds: -------------------------------------------------------------------------------- 1 | s/foo \(..*\)* \(..*\)/\1/ 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-non-participating-submatch/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-non-participating-submatch/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo baz 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-null-re/cmds: -------------------------------------------------------------------------------- 1 | /foo/p 2 | s//./ 3 | w 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-null-re/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-null-re/testdata/input-file: -------------------------------------------------------------------------------- 1 | 123 2 | foobarfoo 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-percent-delim/cmds: -------------------------------------------------------------------------------- 1 | s%foo%%% 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-percent-delim/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-percent-delim/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/substitute-prev-replace-empty/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/foo// 2 | 1,$p 3 | .= 4 | 1,$s/bar/%/ 5 | 1,$p 6 | w 7 | -------------------------------------------------------------------------------- /tests/integration/substitute-prev-replace-empty/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-prev-replace-empty/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:foo123bar 2 | 2:foo456bar 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-prev-replace/cmds: -------------------------------------------------------------------------------- 1 | H 2 | 1,$s/foo/test/1 3 | 1,$p 4 | .= 5 | 1,$s/foo/%/g 6 | 1,$p 7 | .= 8 | 1,$s/test/\%/g 9 | 1,$p 10 | .= 11 | Q 12 | -------------------------------------------------------------------------------- /tests/integration/substitute-prev-replace/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-prev-replace/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobarfoo 2 | foobarfoo 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-regex-syntax-error/cmds: -------------------------------------------------------------------------------- 1 | a 2 | foo 3 | bar 4 | baz 5 | . 6 | 1,$s/[// 7 | -------------------------------------------------------------------------------- /tests/integration/substitute-simple/cmds: -------------------------------------------------------------------------------- 1 | s/foo/bar/ 2 | w 3 | -------------------------------------------------------------------------------- /tests/integration/substitute-simple/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/substitute-simple/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/integration/terminate-after-first-error/cmds: -------------------------------------------------------------------------------- 1 | a 2 | 123 3 | . 4 | W 5 | W 6 | -------------------------------------------------------------------------------- /tests/integration/undo-append/cmds: -------------------------------------------------------------------------------- 1 | a 2 | baz 3 | . 4 | .= 5 | u 6 | .= 7 | w 8 | -------------------------------------------------------------------------------- /tests/integration/undo-append/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-append/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/undo-change/cmds: -------------------------------------------------------------------------------- 1 | 1,2c 2 | insert 3 | three 4 | more lines 5 | . 6 | .= 7 | u 8 | .= 9 | w 10 | -------------------------------------------------------------------------------- /tests/integration/undo-change/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-change/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/undo-copy/cmds: -------------------------------------------------------------------------------- 1 | 1,2c3 2 | .= 3 | u 4 | .= 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/undo-copy/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-copy/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | --- 4 | -------------------------------------------------------------------------------- /tests/integration/undo-delete/cmds: -------------------------------------------------------------------------------- 1 | 4,8d 2 | .= 3 | u 4 | .= 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/undo-delete/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-delete/testdata/input-file: -------------------------------------------------------------------------------- 1 | fronduuia 2 | e 3 | ae 4 | uae 5 | u 6 | ae 7 | u 8 | ae 9 | oo 10 | bar 11 | -------------------------------------------------------------------------------- /tests/integration/undo-edit-command/cmds: -------------------------------------------------------------------------------- 1 | 1,$p 2 | .= 3 | a 4 | foo 5 | . 6 | .= 7 | 1,$p 8 | .= 9 | E testdata/second 10 | .= 11 | 1,$p 12 | .= 13 | u 14 | -------------------------------------------------------------------------------- /tests/integration/undo-edit-command/opts: -------------------------------------------------------------------------------- 1 | testdata/first 2 | -------------------------------------------------------------------------------- /tests/integration/undo-edit-command/testdata/first: -------------------------------------------------------------------------------- 1 | first 2 | -------------------------------------------------------------------------------- /tests/integration/undo-edit-command/testdata/second: -------------------------------------------------------------------------------- 1 | second 2 | -------------------------------------------------------------------------------- /tests/integration/undo-global-non-matched/cmds: -------------------------------------------------------------------------------- 1 | v/foo/a\ 2 | append1\ 3 | append2\ 4 | .\ 5 | i\ 6 | insert1\ 7 | . 8 | .= 9 | 1,$p 10 | u 11 | .= 12 | w 13 | -------------------------------------------------------------------------------- /tests/integration/undo-global-non-matched/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-global-non-matched/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/undo-global/cmds: -------------------------------------------------------------------------------- 1 | g/^/a\ 2 | append1\ 3 | append2\ 4 | .\ 5 | s/[0-9]/2342/ 6 | .= 7 | 1,$p 8 | .= 9 | u 10 | .= 11 | 1,$p 12 | u 13 | .= 14 | w 15 | -------------------------------------------------------------------------------- /tests/integration/undo-global/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-global/testdata/input-file: -------------------------------------------------------------------------------- 1 | 1:foo 2 | 2:bar 3 | -------------------------------------------------------------------------------- /tests/integration/undo-insert/cmds: -------------------------------------------------------------------------------- 1 | 2i 2 | newly inserted 3 | . 4 | .= 5 | u 6 | .= 7 | w 8 | -------------------------------------------------------------------------------- /tests/integration/undo-insert/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-insert/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | 123 4 | -------------------------------------------------------------------------------- /tests/integration/undo-join/cmds: -------------------------------------------------------------------------------- 1 | 1,$j 2 | .= 3 | u 4 | .= 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/undo-join/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-join/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/undo-move/cmds: -------------------------------------------------------------------------------- 1 | 2,3m$ 2 | .= 3 | u 4 | .= 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/undo-move/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-move/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | 123 3 | 456 4 | bar 5 | -------------------------------------------------------------------------------- /tests/integration/undo-nothing/cmds: -------------------------------------------------------------------------------- 1 | .= 2 | 1p 3 | .= 4 | u 5 | .= 6 | -------------------------------------------------------------------------------- /tests/integration/undo-nothing/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-nothing/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobar 2 | foo 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/undo-read/cmds: -------------------------------------------------------------------------------- 1 | r testdata/to-be-read 2 | 1,$p 3 | u 4 | .= 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/undo-read/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-read/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | --- 4 | -------------------------------------------------------------------------------- /tests/integration/undo-read/testdata/to-be-read: -------------------------------------------------------------------------------- 1 | this file is read 2 | using the r command. 3 | -------------------------------------------------------------------------------- /tests/integration/undo-redo/cmds: -------------------------------------------------------------------------------- 1 | i 2 | baz 3 | . 4 | u 5 | .= 6 | 1,$p 7 | u 8 | .= 9 | 1,$p 10 | u 11 | .= 12 | w 13 | -------------------------------------------------------------------------------- /tests/integration/undo-redo/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-redo/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/undo-substitute/cmds: -------------------------------------------------------------------------------- 1 | 1,$s/bar/lol/p 2 | .= 3 | u 4 | .= 5 | w 6 | -------------------------------------------------------------------------------- /tests/integration/undo-substitute/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-substitute/testdata/input-file: -------------------------------------------------------------------------------- 1 | foobar 2 | bar 3 | --- 4 | -------------------------------------------------------------------------------- /tests/integration/undo-undo/cmds: -------------------------------------------------------------------------------- 1 | i 2 | baz 3 | . 4 | .= 5 | 1,$p 6 | .= 7 | u 8 | .= 9 | 1,$p 10 | .= 11 | u 12 | .= 13 | w 14 | -------------------------------------------------------------------------------- /tests/integration/undo-undo/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/undo-undo/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/write-default-empty/cmds: -------------------------------------------------------------------------------- 1 | w testfile 2 | -------------------------------------------------------------------------------- /tests/integration/write-default-empty/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/write-default-empty/testdata/input-file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmeum/edward/3d7b0ff9d425a6eb39397eb9cab3df70b83eaab8/tests/integration/write-default-empty/testdata/input-file -------------------------------------------------------------------------------- /tests/integration/write-default/cmds: -------------------------------------------------------------------------------- 1 | w testfile 2 | -------------------------------------------------------------------------------- /tests/integration/write-default/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/write-default/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/write-empty-to-command/cmds: -------------------------------------------------------------------------------- 1 | w !wc -l 2 | -------------------------------------------------------------------------------- /tests/integration/write-no-file/cmds: -------------------------------------------------------------------------------- 1 | w 2 | -------------------------------------------------------------------------------- /tests/integration/write-partial/cmds: -------------------------------------------------------------------------------- 1 | 1,2w out 2 | -------------------------------------------------------------------------------- /tests/integration/write-partial/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/write-partial/out: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | -------------------------------------------------------------------------------- /tests/integration/write-partial/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/write-to-command-modified/cmds: -------------------------------------------------------------------------------- 1 | a 2 | foobar 3 | . 4 | w !wc -l 5 | q 6 | -------------------------------------------------------------------------------- /tests/integration/write-to-command-modified/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/write-to-command/cmds: -------------------------------------------------------------------------------- 1 | w !wc -l 2 | -------------------------------------------------------------------------------- /tests/integration/write-to-command/testdata/input-file: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/integration/write-update-filename-cmd/cmds: -------------------------------------------------------------------------------- 1 | a 2 | 123 3 | . 4 | w !wc -l 5 | f 6 | -------------------------------------------------------------------------------- /tests/integration/write-update-filename-cmd/testdata/file: -------------------------------------------------------------------------------- 1 | foobarbarfoo 2 | -------------------------------------------------------------------------------- /tests/integration/write-update-filename/cmds: -------------------------------------------------------------------------------- 1 | w testdata/file 2 | f 3 | -------------------------------------------------------------------------------- /tests/integration/write-update-filename/testdata/file: -------------------------------------------------------------------------------- 1 | foobarbarfoo 2 | -------------------------------------------------------------------------------- /tests/integration/zero-address/cmds: -------------------------------------------------------------------------------- 1 | 0a 2 | foo 3 | bar 4 | . 5 | 0r !echo foo 6 | 0i 7 | test 8 | . 9 | w 10 | 0c 11 | change 12 | . 13 | -------------------------------------------------------------------------------- /tests/integration/zero-address/opts: -------------------------------------------------------------------------------- 1 | testdata/input-file 2 | -------------------------------------------------------------------------------- /tests/integration/zero-address/testdata/input-file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmeum/edward/3d7b0ff9d425a6eb39397eb9cab3df70b83eaab8/tests/integration/zero-address/testdata/input-file -------------------------------------------------------------------------------- /tests/interactive/README.md: -------------------------------------------------------------------------------- 1 | # Interactive tests 2 | 3 | The test cases in this directory covers behavior which requires standard input to be a tty. 4 | For example, EOF in input mode or command mode. 5 | The tests require `tmux` to be installed. 6 | Contrary to the default integration tests, these tests require an `expected` output file. 7 | -------------------------------------------------------------------------------- /tests/interactive/eof-confirm-with-quit/cmds: -------------------------------------------------------------------------------- 1 | H 2 | a 3 | foo 4 | . 5 | 1,$p 6 | C-d \ 7 | q 8 | -------------------------------------------------------------------------------- /tests/interactive/eof-confirm-with-quit/expected: -------------------------------------------------------------------------------- 1 | foo 2 | ? 3 | Warning: buffer modified 4 | -------------------------------------------------------------------------------- /tests/interactive/eof-modified-reset/cmds: -------------------------------------------------------------------------------- 1 | H 2 | a 3 | modified 4 | . 5 | C-d \ 6 | 1,$p 7 | C-d \ 8 | 1,$p 9 | C-d \ 10 | C-d \ 11 | -------------------------------------------------------------------------------- /tests/interactive/eof-modified-reset/expected: -------------------------------------------------------------------------------- 1 | ? 2 | Warning: buffer modified 3 | modified 4 | ? 5 | Warning: buffer modified 6 | modified 7 | ? 8 | Warning: buffer modified 9 | -------------------------------------------------------------------------------- /tests/interactive/eof-modified/cmds: -------------------------------------------------------------------------------- 1 | H 2 | a 3 | foo 4 | bar 5 | baz 6 | . 7 | 1,$p 8 | C-d \ 9 | C-d \ 10 | -------------------------------------------------------------------------------- /tests/interactive/eof-modified/expected: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | ? 5 | Warning: buffer modified 6 | -------------------------------------------------------------------------------- /tests/interactive/eof/cmds: -------------------------------------------------------------------------------- 1 | .= 2 | C-d \ 3 | -------------------------------------------------------------------------------- /tests/interactive/eof/expected: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /tests/interactive/input-mode-eof-partial-multiple/cmds: -------------------------------------------------------------------------------- 1 | H 2 | a 3 | foo 4 | bar 5 | baz C-d C-d \ 6 | 1,$p 7 | Q 8 | -------------------------------------------------------------------------------- /tests/interactive/input-mode-eof-partial-multiple/expected: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /tests/interactive/input-mode-eof-partial/cmds: -------------------------------------------------------------------------------- 1 | H 2 | a 3 | foo C-d C-d \ 4 | 1,$p 5 | Q 6 | -------------------------------------------------------------------------------- /tests/interactive/input-mode-eof-partial/expected: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/interactive/input-mode-eof/cmds: -------------------------------------------------------------------------------- 1 | H 2 | a 3 | foo 4 | C-d \ 5 | 1,$p 6 | Q 7 | -------------------------------------------------------------------------------- /tests/interactive/input-mode-eof/expected: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/interactive/interactive-global-eof/cmds: -------------------------------------------------------------------------------- 1 | H 2 | a 3 | foo 4 | bar 5 | faz 6 | . 7 | G/^f/ 8 | s/foo/test/ 9 | C-d \ 10 | 1,$p 11 | Q 12 | -------------------------------------------------------------------------------- /tests/interactive/interactive-global-eof/expected: -------------------------------------------------------------------------------- 1 | foo 2 | faz 3 | ? 4 | unexpected end-of-file 5 | test 6 | bar 7 | faz 8 | -------------------------------------------------------------------------------- /tests/interactive/interactive-unmatched-eof/cmds: -------------------------------------------------------------------------------- 1 | H 2 | a 3 | foo 4 | bar 5 | faz 6 | . 7 | V/^f/ 8 | C-d \ 9 | 1,$p 10 | Q 11 | -------------------------------------------------------------------------------- /tests/interactive/interactive-unmatched-eof/expected: -------------------------------------------------------------------------------- 1 | bar 2 | ? 3 | unexpected end-of-file 4 | foo 5 | bar 6 | faz 7 | -------------------------------------------------------------------------------- /tests/interactive/prompt/cmds: -------------------------------------------------------------------------------- 1 | H 2 | 0p 3 | P 4 | 0p 5 | P 6 | 0p 7 | 0p 8 | q 9 | -------------------------------------------------------------------------------- /tests/interactive/prompt/expected: -------------------------------------------------------------------------------- 1 | ? 2 | ranges cannot start at address zero 3 | *? 4 | ranges cannot start at address zero 5 | *? 6 | ranges cannot start at address zero 7 | ? 8 | ranges cannot start at address zero 9 | -------------------------------------------------------------------------------- /tests/interactive/quit-confirm-with-eof/cmds: -------------------------------------------------------------------------------- 1 | H 2 | a 3 | foo 4 | . 5 | 1,$p 6 | q 7 | C-d \ 8 | -------------------------------------------------------------------------------- /tests/interactive/quit-confirm-with-eof/expected: -------------------------------------------------------------------------------- 1 | foo 2 | ? 3 | Warning: buffer modified 4 | -------------------------------------------------------------------------------- /tests/interactive/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd "$(dirname "$0")" 4 | 5 | if [ -n "$TMUX" ] || ! command -v tmux 1>/dev/null 2>&1; then 6 | echo "Skipping interactive tests" 1>&2 7 | exit 0 8 | fi 9 | 10 | EDWARD="${EDWARD:-$(pwd)/../../bin/edward}" 11 | [ -x "${EDWARD}" ] || \ 12 | abort "Couldn't find edward executable '${EDWARD}'." 13 | 14 | session="ed-test" 15 | cmd="sh -c 'stty -echo && tmux wait-for -S term-setup; env CHICKEN_REPOSITORY_PATH="${CHICKEN_REPOSITORY_PATH}" ${EDWARD}'" 16 | 17 | read_cmd() { 18 | [ $# -eq 0 ] || return 1 19 | 20 | # Terminate all lines with an Enter key unless the line escapes 21 | # the newline with a '\' which is useful for sending control keys. 22 | sed -e 's/\([^\]\)$/\1\nEnter/' -e 's/\\$//' 23 | } 24 | 25 | run_tmux() { 26 | tmux new-session -d -s "${session}" "${cmd}" \; \ 27 | set-option -t "${session}" -w remain-on-exit "on" \; \ 28 | set-option -t "${session}" -w remain-on-exit-format "" \; \ 29 | \ 30 | set-hook -w pane-died \ 31 | "wait-for -S exit-channel" \; \ 32 | \ 33 | wait-for term-setup \; \ 34 | send-keys -t "${session}" $(read_cmd) \; \ 35 | \ 36 | wait-for exit-channel \; \ 37 | capture-pane -S - -E - -t "${session}" -p -C 38 | } 39 | 40 | ret=0 41 | for test in *; do 42 | [ -d "${test}" ] || continue 43 | 44 | name="${test##*/}" 45 | printf "Running test case '%s': " "${name}" 46 | 47 | run_tmux < "${test}/cmds" | awk ' 48 | # Filter out all empty lines between the last non-empty line and EOF. 49 | { 50 | output = output $0 51 | if (length($0) != 0) { 52 | print(output) 53 | output = "" 54 | } 55 | } 56 | ' | cmp -s "${test}/expected" - 57 | 58 | if [ $? -eq 0 ]; then 59 | printf "OK\n" 60 | else 61 | printf "FAIL\n" 62 | ret=1 63 | fi 64 | 65 | tmux kill-session -t "${session}" 66 | done 67 | 68 | exit "${ret}" 69 | -------------------------------------------------------------------------------- /tests/parse-addr.scm: -------------------------------------------------------------------------------- 1 | (import (edward ed addr)) 2 | 3 | (test-parse (addr->range '((current-line) ())) parse-addrs ".") 4 | (test-parse (addr->range '((last-line) ())) parse-addrs "$") 5 | 6 | (define (test-addr-error desc expected input) 7 | (test-parse-error desc expected parse-addrs input)) 8 | 9 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 10 | 11 | (test-group "parse nth line" 12 | (test-parse (addr->range '((nth-line . 42) ())) parse-addrs "42") 13 | (test-addr-error "character in address" "unknown address format" "4x2") 14 | (test-addr-error "chained address without seperator" "unknown address format" "42.")) 15 | 16 | (test-group "parse mark" 17 | (test-parse (addr->range '((marked-line . #\x) ())) parse-addrs "'x") 18 | (test-addr-error "multi-character mark" "invalid mark: expected lowercase character" "'FOO") 19 | (test-addr-error "mark with digit" "invalid mark: expected lowercase character" "'F23")) 20 | 21 | (test-group "parse-forward-bre" 22 | (test-parse (addr->range '((regex-forward . "foo") ())) parse-addrs "/foo/") 23 | (test-parse (addr->range '((regex-forward . "") ())) parse-addrs "//") 24 | (test-parse (addr->range '((regex-forward . "foo/bar") ())) parse-addrs "/foo\\/bar/") 25 | (test-parse (addr->range '((regex-forward . "f.*") ())) parse-addrs "/f.*") 26 | (test-parse (addr->range '((regex-forward . "f??") ())) parse-addrs "/f??/")) 27 | 28 | (test-group "parse-backward-bre" 29 | (test-parse 30 | (addr->range '((regex-backward . "foo") ())) 31 | parse-addrs 32 | "?foo?") 33 | (test-parse 34 | (addr->range '((regex-backward . "") ())) 35 | parse-addrs 36 | "??") 37 | (test-parse 38 | (addr->range '((regex-backward . "foo?bar") ())) 39 | parse-addrs 40 | "?foo\\?bar?") 41 | (test-parse 42 | (addr->range '((regex-backward . "fo\\([a-z]\\)") ())) 43 | parse-addrs 44 | "?fo\\([a-z]\\)?")) 45 | 46 | (test-group "parse-relative" 47 | (test-parse (addr->range '((relative . 5) ())) parse-addrs "+5") 48 | (test-parse (addr->range '((relative . -42) ())) parse-addrs "-42") 49 | (test-parse (addr->range '((relative . 1) ())) parse-addrs "+") 50 | (test-parse (addr->range '((relative . -1) ())) parse-addrs "-")) 51 | 52 | (test-group "parse offsets" 53 | (test-parse (addr->range '((nth-line . 2342) (1))) parse-addrs "2342 +1") 54 | (test-parse (addr->range '((relative . 5) (1 2 3))) parse-addrs "+5 1 2 3") 55 | (test-parse (addr->range '((marked-line . #\f) (23 42))) parse-addrs "'f 23 42") 56 | (test-parse (addr->range '((regex-forward . "foo") (-1 2 -3))) parse-addrs "/foo/ -1 2 -3") 57 | (test-parse (addr->range '((regex-backward . "bar") (+2342))) parse-addrs "?bar?+2342") 58 | (test-parse (addr->range '((nth-line . 23) (-5 +5))) parse-addrs "23-5+5") 59 | (test-addr-error "offset with char" "unknown address format" "23+5-f")) 60 | 61 | (test-group "address ranges" 62 | (test-parse 63 | (list #\,) 64 | parse-addrs ",") 65 | 66 | (test-parse 67 | (list 68 | #\, 69 | (make-addr '(nth-line . 2342))) 70 | parse-addrs ",2342") 71 | 72 | (test-parse 73 | (list 74 | (make-addr '(nth-line . 4223)) 75 | #\,) 76 | parse-addrs "4223,") 77 | 78 | (test-parse 79 | (list #\;) 80 | parse-addrs ";") 81 | 82 | (test-parse 83 | (list 84 | #\; 85 | (make-addr '(nth-line . 9001))) 86 | parse-addrs ";9001") 87 | 88 | (test-parse 89 | (list 90 | (make-addr '(nth-line . 42)) 91 | #\;) 92 | parse-addrs "42;") 93 | 94 | (test-parse 95 | (make-range 96 | (make-addr '(nth-line . 2342)) 97 | #\; 98 | (make-addr '(nth-line . 4223))) 99 | parse-addrs "2342;4223") 100 | 101 | (test-parse 102 | (make-range 103 | (make-addr '(nth-line . 9000)) 104 | #\, 105 | (make-addr '(nth-line . 9001))) 106 | parse-addrs "9000,9001") 107 | 108 | (test-parse 109 | (make-range 110 | (make-addr '(nth-line . 23)) 111 | #\, 112 | (make-addr '(nth-line . 42))) 113 | parse-addrs "23 , 42") 114 | 115 | (test-parse 116 | (make-range 117 | (make-addr '(nth-line . 23) '(23 42)) 118 | #\, 119 | (make-addr '(nth-line . 42) '(42 23))) 120 | parse-addrs "23 +23 +42, 42 +42 +23")) 121 | 122 | (test-group "multiple addresses" 123 | (test-parse 124 | (list 125 | (make-addr '(nth-line . 1)) 126 | #\, 127 | (make-addr '(nth-line . 2)) 128 | #\, 129 | (make-addr '(nth-line . 3))) 130 | parse-addrs "1,2,3") 131 | 132 | (test-parse 133 | (list #\, #\,) 134 | parse-addrs ",,") 135 | 136 | (test-parse 137 | (list #\, #\;) 138 | parse-addrs ",;") 139 | 140 | (test-parse 141 | (list 142 | (make-addr '(nth-line . 7)) 143 | #\, 144 | (make-addr '(nth-line . 5)) 145 | #\,) 146 | parse-addrs "7,5,")) 147 | -------------------------------------------------------------------------------- /tests/parse-cmd.scm: -------------------------------------------------------------------------------- 1 | (import (edward ed cmd) 2 | (edward ed posix) 3 | (edward ed addr) 4 | (edward ed editor)) 5 | 6 | (define (test-parse-cmd desc expected input) 7 | (test desc expected 8 | (let* ((cmd-input (string-append input "\n")) 9 | (cmd-pair (%test-parse (parse-cmd) cmd-input)) 10 | (cmd-addr (car cmd-pair)) 11 | (cmd-args (cmd-args (cdr cmd-pair)))) 12 | (append (list cmd-addr) cmd-args)))) 13 | 14 | (define (test-cmd-error desc expected input) 15 | (test-parse-error desc expected (parse-cmd) input)) 16 | 17 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 18 | 19 | (test-group "append command" 20 | (test-parse-cmd "no arguments" 21 | (list #f '()) "a\n.") 22 | (test-parse-cmd "preceeding whitespaces" 23 | (list #f '()) " a\n.") 24 | (test-parse-cmd "custom address without offset" 25 | (list 26 | (addr->range (make-addr '(nth-line . 2342))) 27 | '()) 28 | "2342 a\n.") 29 | (test-parse-cmd "custom address with offset" 30 | (list 31 | (addr->range (make-addr '(last-line . ()) '(42))) 32 | '()) 33 | "$+42 a\n.")) 34 | 35 | (test-group "read command" 36 | (test-parse-cmd "no arguments" 37 | (list 38 | #f 39 | "") "r") 40 | 41 | (test-parse-cmd "custom address" 42 | (list 43 | (addr->range (make-addr '(nth-line . 42))) 44 | "") "42r") 45 | 46 | (test-parse-cmd "custom address and file" 47 | (list 48 | (addr->range (make-addr '(regex-backward . "foo") '(23 -42))) 49 | "foobar") "?foo? +23 -42 r foobar") 50 | 51 | (test-cmd-error "filename w/o whitespace" "expected newline" "rfoo")) 52 | 53 | (test-group "write command" 54 | (test-parse-cmd "no arguments" 55 | (list 56 | #f 57 | "") "w") 58 | 59 | (test-parse-cmd "custom address and offset, no whitespaces" 60 | (list 61 | (make-range 62 | (make-addr '(current-line)) 63 | (make-addr '(current-line) '(10))) 64 | "foobar") ".,.+10w foobar") 65 | 66 | (test-cmd-error "filename w/o whitespace" "expected newline" "wfoo")) 67 | 68 | (test-group "shell command" 69 | (test-parse-cmd "no replacements" 70 | (list #f (list "echo foobar")) "!echo foobar") 71 | (test-parse-cmd "command with replacement" 72 | (list #f (list "echo " 'current-file)) "!echo %") 73 | (test-parse-cmd "previous command" 74 | (list #f '(previous-command)) "!!") 75 | (test-parse-cmd "previous command appended" 76 | (list #f '(previous-command "foobar")) "!!foobar") 77 | (test-parse-cmd "previous command syntax not start" 78 | (list #f '("foobar !! barfoo")) "!foobar !! barfoo") 79 | (test-parse-cmd "escaped replacement" 80 | (list #f (list "echo %")) "!echo \\%") 81 | (test-parse-cmd "multiple replacements" 82 | (list #f (list "echo " 'current-file " " 'current-file)) "!echo % %")) 83 | 84 | (test-group "global command" 85 | (test-parse-cmd "single command no newline" 86 | (list 87 | (make-range 88 | (make-addr '(nth-line . 1)) 89 | (make-addr '(last-line))) 90 | "foo" 91 | "p\n") "1,$g/foo/p") 92 | 93 | (test-parse-cmd "empty command-list" 94 | (list 95 | #f 96 | "bar" 97 | "p\n") "g/bar/") 98 | 99 | (test-parse-cmd "single trailing whitespace" 100 | (list 101 | (make-range 102 | (make-addr '(nth-line . 1)) 103 | (make-addr '(last-line))) 104 | "foobar" 105 | "p \n") "1,$g/foobar/p ") 106 | 107 | (test-parse-cmd "single command no newline" 108 | (list 109 | (make-range 110 | (make-addr '(nth-line . 23)) 111 | (make-addr '(nth-line . 42))) 112 | "test" 113 | "p \np\n") "23,42g/test/p \\\np") 114 | 115 | (test-cmd-error "missing regex" "expected regex" "1,$gp")) 116 | 117 | (test-group "miscellaneous" 118 | (test-parse-cmd "parse command with trailing blanks" 119 | (list (addr->range (make-addr '(nth-line . 2342))) 120 | '()) 121 | "2342a \n.") 122 | 123 | (test-parse-cmd "append command with suffixed printing command" 124 | (list (addr->range (make-addr '(nth-line . 42))) 125 | '()) 126 | "42an\n.") 127 | 128 | (test-cmd-error "unknown command character" "unknown command" "X") 129 | (test-cmd-error "quit command with argument" "expected newline" "Qn") 130 | (test-cmd-error "append command with argument" "expected newline" "a n")) 131 | -------------------------------------------------------------------------------- /tests/replace.scm: -------------------------------------------------------------------------------- 1 | (import posix-regex (edward replace)) 2 | 3 | (define (test-re str pattern replacement . o) 4 | (let-values (((result modified) 5 | (regex-replace 6 | (make-regex pattern) 7 | (parse (parse-replace #\/) replacement) 8 | str 9 | (if (null? o) 0 (car o))))) 10 | (cons result modified))) 11 | 12 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 13 | 14 | (test-group "backreferences" 15 | (test "single backreference" 16 | '("faz" . #t) 17 | (test-re "foo" "\\([a-z]\\)oo" "\\1az")) 18 | (test "multiple backreferences" 19 | '("bar foo" . #t) 20 | (test-re "foo bar" "\\([a-z]*\\) \\([a-z]*\\)" "\\2 \\1")) 21 | (test "unused backreferences" 22 | '("2" . #t) 23 | (test-re "123" "\\([0-9]\\)\\([0-9]\\)\\([0-9]\\)" "\\2")) 24 | (test "escape subexpression" 25 | '("bar" . #t) 26 | (test-re "\\(foo\\)" "\\\\(foo\\\\)" "bar"))) 27 | 28 | (test-group "ampersand" 29 | (test "append text" 30 | '("foobar" . #t) 31 | (test-re "foo" "foo" "&bar")) 32 | (test "append in middle" 33 | '("foo123bar" . #t) 34 | (test-re "foo1bar" "1" "&23")) 35 | (test "escape ampersand" 36 | '("&bar" . #t) 37 | (test-re "foo" "foo" "\\&bar"))) 38 | 39 | (test-group "replacement amount" 40 | (test "replace first match only" 41 | '("testbarfoo" . #t) 42 | (test-re "foobarfoo" "foo" "test" 1)) 43 | (test "replace all matches" 44 | '("testbartest" . #t) 45 | (test-re "foobarfoo" "foo" "test" 0)) 46 | (test "replace second match only" 47 | '("foobartest" . #t) 48 | (test-re "foobarfoo" "foo" "test" 2))) 49 | 50 | (test-group "miscellaneous" 51 | (test "input string with multibyte character" 52 | '("foo|bar" . #t) 53 | (test-re "fooλbar" "λ" "|")) 54 | (test "replacement with multibyte character" 55 | '("fooλbar" . #t) 56 | (test-re "foo|bar" "|" "λ")) 57 | (test "replace with newline" 58 | '("foo\nbar" . #t) 59 | (test-re "foo|bar" "|" "\\\n")) 60 | (test "non-participating submatch" 61 | '("baz" . #t) 62 | (test-re "foo baz" "foo \\(..*\\)* \\(..*\\)" "\\2\\1")) 63 | (test "empty submatch" 64 | '("matched: " . #t) 65 | (test-re "foo <> baz" 66 | "foo <\\(.*\\)> baz" 67 | "matched: \\1"))) 68 | 69 | (test-group "modified" 70 | (test "no match" 71 | '("foo" . #f) 72 | (test-re "foo" "bar" "test")) 73 | 74 | (test "replace second match" 75 | '(" foo foo bar " . #t) 76 | (test-re " foo foo foo " " foo " " bar " 2))) 77 | -------------------------------------------------------------------------------- /tests/run.scm: -------------------------------------------------------------------------------- 1 | (import r7rs test (edward parse)) 2 | 3 | (define (%test-parse parser input) 4 | (define (parse-with-error parser stream) 5 | (call-with-parse parser stream 0 6 | (lambda (r s i fk) 7 | (if (parse-stream-end? s i) 8 | r 9 | (fk s i "incomplete parse"))) 10 | (lambda (s i reason) (error reason)))) 11 | 12 | (let* ((stream (string->parse-stream input)) 13 | (result (parse-with-error parser stream))) 14 | result)) 15 | 16 | (define (test-parse expected parser input) 17 | (test expected (%test-parse parser input))) 18 | 19 | (define (test-parse-error desc expected parser input) 20 | (let ((r (call-with-current-continuation 21 | (lambda (k) 22 | (with-exception-handler 23 | (lambda (e) (k e)) 24 | (lambda ( ) (k (%test-parse parser input)))))))) 25 | (test desc expected 26 | (if (error-object? r) 27 | (error-object-message r))))) ;; (not (error-object? r)) → undefined 28 | 29 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 30 | 31 | (include-relative "parse-addr.scm") 32 | (include-relative "parse-cmd.scm") 33 | (include-relative "replace.scm") 34 | (include-relative "buffer.scm") 35 | (include-relative "util.scm") 36 | 37 | ;; Exit with non-zero exit status if some test failed. 38 | (test-exit) 39 | -------------------------------------------------------------------------------- /tests/util.scm: -------------------------------------------------------------------------------- 1 | (import (edward util)) 2 | 3 | (test-group "ports->lines" 4 | (test "multiple" 5 | '(("foo" "bar" "baz") . 12) 6 | (let ((port (open-input-string "foo\nbar\nbaz\n"))) 7 | (port->lines port))) 8 | 9 | (test "empty" 10 | '(() . 0) 11 | (let ((port (open-input-string ""))) 12 | (port->lines port)))) 13 | 14 | (test-group "count-bytes" 15 | (test "ascii string" 6 (count-bytes "foobar")) 16 | (test "multibyte string" 2 (count-bytes "λ"))) 17 | 18 | (test-group "path-join" 19 | (test "empty" "" (path-join)) 20 | (test "single" "foo" (path-join "foo")) 21 | (test "multiple" "foo/bar/baz" (path-join "foo" "bar" "baz"))) 22 | --------------------------------------------------------------------------------