README.org

April 1, 2024 ยท View on GitHub

#+TITLE: text.editing README #+AUTHOR: Jan Moringen #+EMAIL: jmoringe@techfak.uni-bielefeld.de #+LANGUAGE: en

#+OPTIONS: toc:nil num:nil #+SEQ_TODO: TODO STARTED | DONE

  • Introduction

    This library provides protocols and implementations of those protocols for text editing operations which are required by, for example, text editors or commandline processors (like REPLs). This library relies on the [[https://github.com/Robert-Strandh/cluffer][Cluffer]] library for the fundamental concepts of buffers, lines and cursors. The functionality provided by this library includes:

    • Cursor movement (by various "units")

    • Insertion and deletion (by various "units")

    • Transformations (for example changing case or transposing)

    • Killing, copying and inserting

    • Multiple cursors

    • "Mark" cursors and regions

    • Undo (work in progress)

    • Operations on expression (like paredit for Emacs)

    • Search and incremental search

    • Abbreviations (work in progress)

    This library does not provide

    This library is under active development. Its ASDF system structure, package structure, exported symbols and protocols may change at any time. Consult the NEWS file or the "Changelog" section of the manual for lists of changes in specific versions.

    This document only gives a very brief overview and highlights some features. Proper documentation can be found in the file:documentation directory.

  • Usage Overview

    Using this library typically requires a buffer class defined by the client which includes the desired mixin classes. For example

    #+BEGIN_SRC lisp :exports both :results value verbatim :wrap EXAMPLE (defclass my-buffer (text.editing:multiple-site-mixin text.editing:site-mixin cluffer-standard-buffer:buffer) ()) #+END_SRC

    #+RESULTS: #+BEGIN_EXAMPLE # #+END_EXAMPLE

    This buffer class is like a Cluffer buffer but also has a primary and zero or more additional sites. Creating an instance of the buffer class automatically creates the primary site an attaches its point cursor to the initial line of the buffer:

    #+BEGIN_SRC lisp :exports both :results output verbatim :wrap EXAMPLE (defvar my-buffer (make-instance 'my-buffer :initial-line (make-instance 'cluffer-standard-line:closed-line)))

    (print my-buffer) (print (text.editing:site my-buffer)) (print (text.editing:sites my-buffer)) (print (text.editing:point (text.editing:site my-buffer))) #+END_SRC

    #+RESULTS: #+BEGIN_EXAMPLE

    #<MY-BUFFER 1 line 0 items {1006791483}> #<SITE 0:0 {1006B03D03}> (#<SITE 0:0 {1006B03D03}>) #<CLUFFER-STANDARD-LINE:RIGHT-STICKY-CURSOR 0:0 {1006D4EDC3}> #+END_EXAMPLE

    This buffer instance is usable with the operations provided by this library:

    #+BEGIN_SRC lisp :exports both :results values verbatim :wrap EXAMPLE (defvar point (text.editing:point my-buffer)) (setf (text.editing:items point text.editing:buffer :forward) (format nil "one~%two!%three%")) (defun summary () (values (coerce (text.editing:items point text.editing:buffer :forward) 'string) (text.editing:sites my-buffer))) (summary) #+END_SRC

    #+RESULTS: #+BEGIN_EXAMPLE "one two! three " (#<SITE 3:0 {1006B03D03}>) #+END_EXAMPLE

    #+BEGIN_SRC lisp :exports both :results values verbatim :wrap EXAMPLE (text.editing:change-case point text.editing:word :backward :up) (summary) #+END_SRC

    #+RESULTS: #+BEGIN_EXAMPLE "one two! THREE " (#<SITE 2:0 {1006B03D03}>) #+END_EXAMPLE

    While many operations can be applied directly to a cursor, it is preferable use to the "operation protocol" and let the library figure out how and to which object to apply the operation in question:

    #+BEGIN_SRC lisp :exports both :results values verbatim :wrap EXAMPLE (text.editing:perform my-buffer 'text.editing:move text.editing:word :backward) (text.editing:perform my-buffer 'text.editing:delete text.editing:line :forward) (summary) #+END_SRC

    #+RESULTS: #+BEGIN_EXAMPLE "one

    THREE " (#<SITE 1:0 {1006B03D03}>) #+END_EXAMPLE

    The deleted word is now in the insertion stack (which is like the "kill ring" in Emacs) and can be inserted:

    #+BEGIN_SRC lisp :exports both :results values verbatim :wrap EXAMPLE (loop :repeat 3 :do (text.editing:perform my-buffer 'text.editing:yank :forward)) (summary) #+END_SRC

    #+RESULTS: #+BEGIN_EXAMPLE "one two!two!two! THREE " (#<SITE 1:12 {1006B03D03}>) #+END_EXAMPLE

    It is easy to see how the operation protocol comes into play when multiple sites are used:

    #+BEGIN_SRC lisp :exports both :results values verbatim :wrap EXAMPLE (text.editing:push-site-relative my-buffer text.editing:line :forward) (summary) #+END_SRC

    #+RESULTS: #+BEGIN_EXAMPLE "one two!two!two! THREE " (#<SITE 1:12 {1006B03D03}> #<SITE 2:5 {100AE016D3}>) #+END_EXAMPLE

    #+BEGIN_SRC lisp :exports both :results values verbatim :wrap EXAMPLE (text.editing:perform my-buffer 'text.editing:move text.editing:line-boundary :backward) (text.editing:perform my-buffer 'text.editing:change-case text.editing:word :forward :capital) (summary) #+END_SRC

    #+RESULTS: #+BEGIN_EXAMPLE "one Two!two!two! Three " (#<SITE 1:3 {1006B03D03}> #<SITE 2:5 {100AE016D3}>) #+END_EXAMPLE