summaryrefslogtreecommitdiff
path: root/modes
diff options
context:
space:
mode:
Diffstat (limited to 'modes')
-rw-r--r--modes/Concepts.txt298
-rw-r--r--modes/modes.el97
2 files changed, 395 insertions, 0 deletions
diff --git a/modes/Concepts.txt b/modes/Concepts.txt
new file mode 100644
index 0000000..e9cfac4
--- /dev/null
+++ b/modes/Concepts.txt
@@ -0,0 +1,298 @@
+Title: Concepts and designs of modes
+Author: JSDurand
+Created: 2021-01-01
+-------------------------------------
+
+======================================================================
+ Introduction
+======================================================================
+
+In this document, and in this document only, sometimes we refer to
+Emacs as "the editor", though the situations referred to are
+definitely different from those of other editors, and the editor Emacs
+does not represent other editors in any way. This reference is solely
+out of personal preferences.
+
+When we edit texts through a text editor, since there are a lot of
+functionalities we would like to perform in the editor, we oft end up
+with binding many keys with various functions in the editor. This
+causes a problem: the keys are either too long to conveniently press
+or too compactly packaged that it requires experience to remember and
+use them at ease (what if we can execute the form “(require
+'experience)” in Emacs ;P).
+
+The proposed way in this document to solve this dilemma is to make
+keys behave according to the "contexts" of the editor. That is to say,
+we are using the same key to perform such different tasks as to switch
+buffers, to select different windows, and even to pop up a different
+mail to read.
+
+To be honest, there is nothing new in this idea: it is the core idea
+of the so-called "modal editing". And there are numerous packages that
+implement similar ideas in Emacs already, such as evil, god-mode, or
+even viper, just to name a few.
+
+The difference of my implementation with other packages is that I
+would like to first push this idea to a more general level, before
+specialising to some specific states. In other words, the modes should
+reflect more dedicated states of the editor and the current task I am
+performing. More precisely, when I am trying to switch buffers, I
+shall be in a "buffer mode", that permits me to switch buffers just by
+arrow keys, or whatever keys I have chosen for the concepts of "up"
+and "down". Moreover, the concepts include not only four directions
+but also "previous" and "next", whose functions are to switch to the
+previously used and the next-to-be-used buffer respectively.
+
+Simply put, a mode is nothing but a correspondence from concepts to
+functions. And the user should decide how to map these concepts to
+keys.
+
+Then this document tries to record the modes that I accumulated
+through the use of the editor.
+
+
+
+======================================================================
+ Analogy with the languages
+======================================================================
+
+If we view pressing keys as the user speaking to the computer, then
+these keypresses of a user form a "language", in a formal sense. The
+letters are the keys on the keyboard (so each user has a potentially
+different set of letters), and the words are valid key sequences, as
+per the Emacs parlance. For example, in the built-in language of
+Emacs, the word "C-x 4 d" means to open a directory in another window.
+
+There are some characteristics of this kind of languages. The most
+obvious characteristics is that the verbs are all in one of two
+"moods" (this term comes from Latin grammar if my memory serves me):
+imperative and interrogative, since this language serves the only
+purpose for the user to give the computer commands, or to query some
+states.
+
+Another characteristics is that, there are a myriad of "tenses",
+"conjugations" and "declensions". These refer to the fact that a key's
+meaning depends upon the contexts. So we can view "C-x 4 d" as a
+conjugation of the verb "C-x d", which is to open a directory in the
+current window.
+
+However, as one of the reasons that the Sanskrit language is deemed
+not easy to learn is that it has numerous declensions, conjugations,
+liaisons, and irregularities, the same thing happens with the
+key-binding language. If a key-binding language has too many tenses
+and irregularities, then it is difficult to remember, to use, and to
+"speak". And, from my point of view, the built-in key-binding language
+of the editor is too difficult to use, however logical the design of
+that language may be.
+
+The aim of this document is thus to solve this problem, for me and for
+me only, at the same time laying some foundation upon which others may
+build their own languages to solve their own problems, in the future.
+
+
+
+======================================================================
+ The solution in terms of the analogy with the languages
+======================================================================
+
+So what does our solution mean in terms of the above analogy with the
+languages? I think this is the difference between the agglutinative
+languages and analytical languages.
+
+According to Wikipedia, "an agglutinative language is a type of
+synthetic languages with morphology that primarily uses
+agglutination." And agglutination is "a linguistic process pertaining
+to derivational morphology in which complex words are formed by
+stringing together morphemes without changing them in spelling or
+phonetics."
+
+Basically, this is one of the characteristics of the default Emacs
+language: concatenating affixes after affixes, or prefixes.
+
+Again according to Wikipedia, "an analytic language is a language that
+primarily conveys relationships between words in sentences by way of
+helper words (particles, prepositions, etc.) and word order, as
+opposed to using inflections (changing the form of a word to convey
+its role in the sentence)."
+
+In our contexts, this means we use helper words (key sequences) to
+alter the meanings of keys. In addition, it is also a common oral
+practice to use "persistent" contexts. For example, (I don't know
+about English, so here I refer to the situation with my mother tongue
+Chinese), when telling a story, after one declares this happened in
+the past, we can safely use verbs without tenses and expect that the
+listener understands this is a past action. Hence the effect I want to
+achieve is that we can expect the editor to understand that after we
+changed our contexts, the keys have a different meaning now.
+
+
+
+======================================================================
+ Major modes and minor modes
+======================================================================
+
+One might wonder why I don't just use Emacs' built-in major modes and
+minor modes, as those sound like a generalization of the ideas of
+modes already. In this regard, I really think my idea of modes is just
+like a minor mode, in that it is not directly relateed to the file or
+the buffer being operated on. Rather it concerns the intention of the
+user. And in effect we can implement the modes as depicted above using
+nothing but major and minor modes.
+
+There is a problem though: the minor modes control the keymaps through
+the variable "minor-mode-map-alist". It is a plain association list
+that associates minor-mode symbols to keymaps. Wheneven the minor-mode
+symbol has a non-nil value, the associated keymaps is in effect.
+However, the order of priority for these maps is the same as the order
+of appearance in this association list. This means we might sometimes
+get unpredictable results when we try to activate certain functions in
+our modes. Therefore, to avoid this problem, I decided to avail of a
+higher-priority map, namely "emulation-mode-map-alists". And it
+functions in the same way as the former.
+
+
+
+======================================================================
+ General concepts
+======================================================================
+
+Some concepts are in a sense "universal" to all modes. These are the
+concepts that don't concern with the specific functionalities of
+modes, but rather with the abstract notion of modes.
+
+quit - Quit a mode, and nothing else.
+quit & bury - Quit a mode and bury the current buffer.
+quit & quit - Quit a mode and quit the selected window.
+quit & kill - Quit a mode and kill the current buffer.
+
+
+
+======================================================================
+ Buffer mode
+======================================================================
+
+The first mode that I desire is a mode that operates on the buffers.
+As Protesilaos Stavrou rightly observed, the true power of Emacs lies
+in its handling of the buffers, since this frees the limited screen
+estate and leverages the power of the computer to manage the editing
+resources. So naturally there are a lot of operations related to
+buffers that are quite useful to us. Below is a list of the
+correspondence between concepts and functions that I can think of.
+
+up - The previous buffer in the list of buffers.
+down - The next buffer in the list of buffers.
+previous - The previously used buffer.
+next - The next-to-be-used buffer.
+ In practice this means the buffers that the user left by
+ going to the previous buffer.
+jump/show - Either use the completion framework to select a buffer
+ or display an interactive list of buffers, i.e. ibuffer.
+ This can first call ibuffer, and the second call uses
+ the completion framework.
+last - Whether this deserves an independent concept is still
+ debatable. This just switches to the last used buffer. If
+ called repeatedly, it switches between two buffers.
+save - Save a buffer.
+ I am used to frequently save buffers, so it is important
+ to access this conveniently.
+kill - Kill and save a buffer.
+delete - Simply kill a buffer.
+rename - Rename a buffer.
+search - Search through a buffer.
+
+
+
+======================================================================
+ Window mode
+======================================================================
+
+
+To be honest I don't believe I really need to manage windows. Rather I
+would like Emacs to automatically handle the windows the way I want.
+But since it is too difficult to guess my mind, this mode is still
+relevant.
+
+up - Go up a window.
+down - Go down a window.
+left - Go left a window.
+right - Go right a window.
+jump/show - Use the completion framework to choose a window to go to.
+ It might make sense to have a buffer list all windows that
+ I can jump to, just like an "iwindow".
+save - Save a window configuration.
+load - Load a window configuration.
+delete - Kill a window.
+
+
+
+======================================================================
+ Help mode
+======================================================================
+
+The idea is to make the help system behave more conveniently. For
+example, currently if the user opens a file thruogh the help system,
+then the user is put in the major mode corresponding to that file. I
+think it might be more convenient if the user is still in the help
+mode. When and only when the user chooses to exit the help mode,
+should the user be put in the major mode corresponding to that file.
+
+up - Scroll "down".
+down - Scroll "up".
+previous - Go to the previous help buffer.
+next - Go to the next help buffer.
+search - Searching through the help buffer is also important.
+
+
+
+======================================================================
+ Selection mode
+======================================================================
+
+I haven't decided yet whether this should be a separate mode or just a
+concept for other different modes that turn the current "object" into
+a selection.
+
+
+
+======================================================================
+ View mode, or the screen mode
+======================================================================
+
+This mode of Emacs really surprised me when I first learned about its
+existence. It hinted at endless possibilities, in some sense. But it
+does not fully meet my expectations.
+
+I view document frequently. I believe that writing is a reflection of
+thinking, and while I am thinking, I like to scroll through the
+document to answer such questions as what have I written, does the
+current writing follow the outline or the sketch in my mind, do the
+writings hint at some directions that I didn't notice before I wrote
+them down, and the rest. Consequently, it is am important part of my
+editing activity to view the documents.
+
+Since my screen is limited, the occassion occurs frequently that I
+need to scroll the document to view some parts of it. In addition, I
+like to highlight things, so it is equally important to easily select
+or highlight arbitrary things on the screen. Thus my primary focus in
+viewing documents are scrolling, positioning the cursor, highlighting,
+and (re)centering the buffer.
+
+To be more precise, I would like the directional concepts to be
+directly (no pun intended) related to the scrolling of the documents;
+this covers eight directional concepts (up, down, left, right, and
+their "maximal" versions).
+
+In addition to the above, I would also like to have special "concepts"
+to go to the top, the middle, and the bottom of the screen.
+
+Lastly, about the jump/show concept I shall talk a little. I used to
+love the package "avy", which permits the user to jump to anywhere on
+the screen by matching either a line, a character, or any character
+sequence the user inputs. Upon further reflection, however, I do not
+find anything this package offers that a plain old "interactive
+search" does not offer.
+
+By the way, instead of the name "view mode" it would probably be
+better to call it "screen mode", since it concerns the screens. And to
+view is a verb, not a state of the editor; after all, we are always
+viewing something on the editor, unless it crashes.
diff --git a/modes/modes.el b/modes/modes.el
new file mode 100644
index 0000000..538ab93
--- /dev/null
+++ b/modes/modes.el
@@ -0,0 +1,97 @@
+;;; A modal interface
+
+;;; Dictionary
+
+;; ;;;###autoload
+;; (defvar modes-concepts
+;; (list 'down 'up 'left 'right 'next 'previous
+;; 'down-max 'up-max 'left-max 'right-max 'next-max 'previous-max
+;; 'jump)
+;; "The concepts that a mode can define.")
+
+
+;;;###autoload
+(defvar modes-concept-keymap
+ (list
+ (cons 'down '(?j down))
+ (cons 'up '(?k up))
+ (cons 'right '(?l right))
+ (cons 'left '(?h left))
+ (cons 'forward ?n)
+ (cons 'backward ?p)
+ (cons 'down-max '([?J] S-down))
+ (cons 'up-max '([?K] S-up))
+ (cons 'right-max '([?L] S-right))
+ (cons 'left-max '([?H] S-left))
+ (cons 'forwrad-max ?N)
+ (cons 'backward-max ?P)
+ (cons 'jump 'tab)
+ (cons 'other ?o)
+ (cons 'undo ?u)
+ (cons 'redo ?U))
+ "An alist that maps concepts to keys.")
+
+;;;###autoload
+(defvar modes-map-alist (cons (cons 'modes-mode '(keymap "Modes alist")) nil)
+ "The current mode map.")
+
+(push 'modes-map-alist emulation-mode-map-alists)
+
+;;;###autoload
+(define-minor-mode modes-mode "A modal interface" nil "Modes" nil :global t)
+
+;;;###autoload
+(defun modes-process-key (key)
+ "Process keys appropriately.
+The return value is a list of keys acceptable by `define-key'."
+ (cond
+ ((stringp key) (list (kbd key)))
+ ((vectorp key) (list key))
+ ((or (symbolp key) (integerp key)) (list (vector key)))
+ ((listp key)
+ (mapcar (lambda (k)
+ (cond
+ ((stringp k) (kbd k))
+ ((vectorp k) k)
+ ((integerp k) (vector k))
+ ((symbolp k) (vector k))
+ (t (user-error "Unsupported key: %S" k))))
+ key))
+ (t (user-error "Unsupported key: %S" key))))
+
+;;;###autoload
+(defun modes-set-mode (alist)
+ "Set a mode.
+A mode is just an ALIST between concepts and functions."
+ (let ((map (cons 'keymap "Modes")))
+ (dolist (concept-to-function alist)
+ (let* ((key (or
+ (alist-get (car concept-to-function)
+ modes-concept-keymap)
+ (error "Unsupported concept: %S" (car concept-to-function))))
+ (keys (modes-process-key key))
+ (fun (cdr concept-to-function)))
+ (mapc (lambda (k) (define-key map k fun)) keys)))
+ (set 'modes-map-alist (list (cons 'modes-mode map)))))
+
+;;; Modes
+
+;;; buffer mode
+
+(defun switch-to-last-buffer ()
+ "Switch to the last buffer."
+ (interactive)
+ (switch-to-buffer (other-buffer)))
+
+(set 'modes-buffer-mode
+ '((down . next-buffer)
+ (up . previous-buffer)
+ (other . switch-to-last-buffer)
+ (jump . ibuffer)))
+
+
+
+
+
+
+