Module: deuce-internals Synopsis: The Deuce editor Author: Scott McKay Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// Editors define protocol <> () getter editor-frames (editor :: ) => (frames :: ); setter editor-frames-setter (frames :: , editor :: ) => (frames :: ); getter editor-windows (editor :: ) => (windows :: ); setter editor-windows-setter (windows :: , editor :: ) => (windows :: ); getter editor-buffers (editor :: ) => (buffers :: ); setter editor-buffers-setter (buffers :: , editor :: ) => (buffers :: ); getter editor-source-containers (editor :: ) => (containers :: ); setter editor-source-containers-setter (containers :: , editor :: ) => (containers :: ); getter editor-kill-history (editor :: ) => (history :: ); getter editor-lock (editor :: ) => (lock :: ); end protocol <>; // An is a class that maintains the global state for a set of // editor frames. For example, all the buffers managed by an editor have // their redisplay tracked in all of the windows managed by the same editor. // Deuce back-ends are expected to supply a concrete implementation class // that is a subclass of . define open abstract class () // Stretchy vectors are thread-safe, so we don't need to lock them sealed slot editor-frames :: = make(), init-keyword: frames:; sealed slot editor-windows :: = make(), init-keyword: windows:; sealed slot editor-buffers :: = make(), init-keyword: buffers:; //--- Should this be a case-insensitive string table? sealed slot editor-source-containers :: = make(), init-keyword: containers:; sealed slot editor-kill-history :: = make(), init-keyword: kill-history:; sealed slot editor-policy :: = copy-policy($default-editor-policy), init-keyword: policy:; sealed constant slot editor-lock :: = make(); // Cached tables for Boyer-Moore searching, shared by all frames sealed slot editor-search-string :: false-or() = #f, setter: %search-string-setter; sealed slot editor-replace-string :: false-or() = #f; sealed slot editor-reverse-search? :: = #f; sealed slot editor-case-sensitive-search? :: = #f; sealed slot editor-whole-word-search? :: = #f; sealed slot editor-skip-table :: false-or() = #f; sealed slot editor-reoccurrence-table :: false-or() = #f; end class ; define sealed class () end class ; define sealed domain make (singleton()); define sealed domain initialize (); define sealed method editor-search-string-setter (search-string :: false-or(), editor :: ) => (search-string :: false-or()) unless (search-string = editor-search-string(editor)) // Invalidate the Boyer-Moore search caches, but don't compute them // until we need them editor.%search-string := search-string; editor-skip-table(editor) := #f; editor-reoccurrence-table(editor) := #f; for (frame :: in editor-frames(editor)) frame-search-string-found?(frame) := #f end end end method editor-search-string-setter; define method find-buffer (editor :: , name :: ) => (buffer :: false-or()) let buffers = editor-buffers(editor); find-value(buffers, //--- Should this use case-insensitive compare? method (b) buffer-name(b) = name end) end method find-buffer; define method find-buffer-from-pathname (editor :: , pathname :: ) => (buffer :: false-or()) find-buffer(editor, pathname->buffer-name(pathname)) end method find-buffer-from-pathname; /// Editor frames define constant = one-of(#"cancel", #"number", #"motion", #"line-motion", #"mark", #"scroll", #"display", #"insert", #"delete", #"kill", #"yank", #"yank-no-motion", #"undo", #"redo", #"file", #"compile", #"shell", #"macro", #"complete", #"dynamic-complete", #"browse", #"mail", #"version-control", #f); define constant = one-of(#"digits", #"sign", #"universal", #"universal-digits", #"universal-sign", #f); define constant = one-of(#"forward", #"backward", #f); // Backend classes can add methods to this to be notified of a // change in the search state. The value is the buffer in which the // search string was found. define open generic frame-search-string-found?-setter (found? :: false-or(), frame :: ) => (found? :: false-or()); // This class is separated out from because // we sometimes want embedded panes to maintain all this stuff themselves define open abstract class () // Point back to the editor the owns this frame sealed slot frame-editor :: = $null-editor, init-keyword: editor:; // The current buffer and window sealed slot frame-buffer :: false-or() = #f, init-keyword: buffer:; sealed slot frame-window :: false-or() = #f, init-keyword: window:; // The current command table, installed by the buffer's major mode sealed slot frame-command-set :: = $standard-command-set, setter: %command-set-setter, init-keyword: command-set:; // State for reading of prefixed commands, e.g., c-X c-F sealed slot frame-command-state :: = standard-command-table($standard-command-set); sealed slot frame-command = #f; sealed slot frame-command-character = #f; sealed slot frame-command-modifiers :: = 0; sealed slot frame-last-command = #f; sealed slot frame-last-command-type :: = #f; // Command hooks sealed slot frame-before-command-hooks = #(); sealed slot frame-after-command-hooks = #(); // Accumulated argument state for commands sealed slot frame-numeric-arg :: = 1; sealed slot frame-numeric-arg-state :: = #f; // Current keyboard macro, if any sealed slot frame-keyboard-macro :: false-or() = #f; // Incremental search state sealed slot frame-isearch-trail :: = #(); sealed slot frame-isearch-direction :: = #f; sealed slot frame-isearch-move-mark? :: = #f; sealed slot frame-isearch-last-string :: false-or() = #f; // Search&Replace state slot frame-search-string-found? :: false-or() = #f; // _not_ sealed // Dynamic completion state sealed slot frame-dynamic-completion-state = #f; end class ; define method initialize (frame :: , #key) => () next-method(); let frames = editor-frames(frame-editor(frame)); add!(frames, frame); frame-command-state(frame) := standard-command-table(frame-command-set(frame)) end method initialize; define sealed method frame-command-set-setter (command-set :: , frame :: ) => (command-set :: ) frame.%command-set := command-set; frame-command-state(frame) := standard-command-table(command-set); command-set end method frame-command-set-setter; // An editor frame is a single editor with a current buffer, displaying in // a particular window. The current buffer is one of the buffers managed // by the owning . // Deuce back-ends are expected to supply a concrete implementation class // that is a subclass of . define open abstract class () end class ; define sealed class () end class ; define sealed domain make (singleton()); define sealed domain initialize (); // NB: this may queue an exit event, and therefore not necessarily exit immediately define open generic exit-editor (frame :: ) => (); // Default method is a no-op // In particular, embedded Deuce gadgets want this no-op behavior define method exit-editor (frame :: ) => () #f end method exit-editor; // The editor frame for "this" command loop // The type is 'false-or' for bootstrapping reasons... define thread variable *editor-frame* :: false-or() = #f;