Code Services
pyssel/editor/services is what the code editor asks of the Lisp it runs
in, as LispWorks' IDE asks LispWorks: where a name is defined, who calls a
function, completions, argument lists, help, a macro's expansion,
compiling and evaluating with the compiler's notes at their places, a
thread's frames in the debugger, and objects' parts, as an inspector shows
them. It
knows nothing of the user interface, so the Script screen, the REPL, the
debugger and your programs ask it alike. Texts are
Lisp texts, and a place's forms are read in the package
text-package finds there, as SLY finds a buffer's.
(pyssel/editor/services:argument-hint "(subseq string " 0 15)
;; => "(subseq sequence start &optional end)", 17, 22
(mapcar #'pyssel/editor/services:definition-title
(pyssel/editor/services:find-definitions 'print-object))
;; => ("(defgeneric print-object)" "(defmethod print-object (editor t))" ...)
Symbols and definitions
token-symbol gives the symbol a token names in a package, as the reader
would read it, but interning nothing. find-definitions gives a name's
definitions, a definition each, as SLY's M-. finds them: of a variable,
a constant, a type, a symbol macro, a macro, a compiler macro, a
function, a generic function and each of its methods, a SETF expander, a
structure, a condition, a class, a method combination and a package of
that name, each with its kind, its title, as (defmethod draw :before (sprite)), its file and the line and column its form starts at, a
structure's accessor at its slot. The place is where the form is in the
file as it is now: where it was compiled while the file is as it was,
or while its top-level form still defines the name, else at the first
form that does. who-calls and who-macroexpands give the functions
that call a function, or where a macro expands, as SBCL's cross
references know them.
Completion and argument hints
completions gives the completions of a symbol's text as typed, as
SLY's flex completion finds them: the characters typed in order, each
after the one before, in upper case, keywords for a text that starts
with a colon, the symbols the package reaches, the external symbols of
the others with their packages' shortest names, uite for
ui:text-edit, and with two colons, every package's; the best matches
first, each a completion with its text, its symbol, its kind and where
the text typed matched. A completion over the 55,000 external symbols
of an editor's Lisp takes about 4 ms.
argument-hint gives the lambda list of the operator of the form a place
is in, as SLY's autodoc shows it, and where in it the parameter the
place's argument binds starts and ends: out through four lists at most,
into a macro's destructuring lists, a keyword parameter by its keyword,
and make-instance of a quoted class with the class's initargs.
Help and expansions
symbol-help gives what a Lisp knows of a symbol as text: what it names,
an operator with its lambda list, a variable with its value, a class with
its superclasses and slots, each with its documentation. expand-form
expands a macro form once, or with :all, every macro in it.
Compiling and evaluating
compile-form compiles the text of a form at a place of a file, as SLY's
C-c C-c, and compile-and-load-file a file, as C-c C-k, each to a
temporary file, and loads what compiled unless the compilation failed, as
on an error or a warning that is not a style warning. Each gives a
compilation: whether it failed and whether it loaded, and its
compiler-notes, each with its severity, :error, :read-error,
:warning, :style-warning, :note or :redefinition, its message and
where the form it concerns starts and ends in the file, read from SBCL's
compiler error context. The definitions a form compiled makes are found
at its place in its file. evaluate-form evaluates a form's text in a
package and gives its values.
The debugger
A debugger hook runs on the thread whose error or break entered the
debugger, its stack as it was, so these are called there, as the editor's
debugger calls them. backtrace gives the thread's
frames, a frame each, with its index and its description, the call it
stands for, from the frame that called error or break, :start and
:count saying which; frame-locals a frame's variables that have a
value where it is, as (symbol . value); frame-source where its form
is in its file as the file is now, as find-definitions finds a
definition; frame-package the package of its function's name; and
evaluate-in-frame evaluates a form's text in its lexical environment,
its variables visible, and gives its values. A frame is valid only on
its thread, while the thread stays in the debugger.
(defun my-failing-function (n)
(error "~D is too few." n))
(let ((sb-ext:*invoke-debugger-hook* ; a hook, as the editor's
(lambda (condition hook)
(declare (ignore hook))
(let ((frame (first (pyssel/editor/services:backtrace :count 1))))
(print (pyssel/editor/services:frame-description frame))
(print (pyssel/editor/services:frame-locals frame))
(invoke-restart (find-restart 'abort condition))))))
(with-simple-restart (abort "Leave.")
(my-failing-function 4)))
;; prints "(MY-FAILING-FUNCTION 4)" and ((N . 4))
Inspecting
object-parts gives the parts of an object an inspector shows, as SLY's
inspector shows them, a part each, with its label, its value and
whether it has one, as an unbound slot has not: an instance's, a
structure's or a condition's slots; a list's or a vector's elements, and
a dotted list's tail; an array's dimensions and elements; a hash table's
test, count and entries; a symbol's name, package, value, function and
properties; a package's names, uses and symbols; a function's name,
lambda list and documentation; a pathname's components; a character's
code and name; a ratio's and a complex's parts. It gives the first
+inspected-parts+, 500, and how many more there are, or nil for a
circular list. It is a generic function, which a program extends for
objects of its own. object-title heads an object, its type and how it
prints, and object-text prints one as an inspector shows it, on one
line, cut short.
(mapcar #'pyssel/editor/services:part-label
(pyssel/editor/services:object-parts (make-hash-table)))
;; => ("test" "count")
Thread rules
Each function answers on the thread that calls it and keeps no state between calls; the debugger's, on the thread in the debugger. Compiling and evaluating run there, which their output and errors reach, so the editor calls them on a thread of its own; compiling holds SBCL's lock of the compiler while it works.
Getting started
The core
Drawing
Scenes
User interface
Games and the editor
- Playing a Game
- Projects
- The Editor
- The File System Dock
- The Script Screen
- The REPL
- The Debugger
- Lisp Text
- Code Services
- Project Manager
- Undo and Redo
- Exporting
The project