1
0
Fork 0
cl-sites/lispcookbook.github.io/cl-cookbook/lispworks.html
2023-10-25 11:23:21 +02:00

704 lines
31 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta name="generator" content=
"HTML Tidy for HTML5 for Linux version 5.2.0">
<title>LispWorks review</title>
<meta charset="utf-8">
<meta name="description" content="A collection of examples of using Common Lisp">
<meta name="viewport" content=
"width=device-width, initial-scale=1">
<link rel="icon" href=
"assets/cl-logo-blue.png"/>
<link rel="stylesheet" href=
"assets/style.css">
<script type="text/javascript" src=
"assets/highlight-lisp.js">
</script>
<script type="text/javascript" src=
"assets/jquery-3.2.1.min.js">
</script>
<script type="text/javascript" src=
"assets/jquery.toc/jquery.toc.min.js">
</script>
<script type="text/javascript" src=
"assets/toggle-toc.js">
</script>
<link rel="stylesheet" href=
"assets/github.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<h1 id="title-xs"><a href="index.html">The Common Lisp Cookbook</a> &ndash; LispWorks review</h1>
<div id="logo-container">
<a href="index.html">
<img id="logo" src="assets/cl-logo-blue.png"/>
</a>
<div id="searchform-container">
<form onsubmit="duckSearch()" action="javascript:void(0)">
<input id="searchField" type="text" value="" placeholder="Search...">
</form>
</div>
<div id="toc-container" class="toc-close">
<div id="toc-title">Table of Contents</div>
<ul id="toc" class="list-unstyled"></ul>
</div>
</div>
<div id="content-container">
<h1 id="title-non-xs"><a href="index.html">The Common Lisp Cookbook</a> &ndash; LispWorks review</h1>
<!-- Announcement we can keep for 1 month or more. I remove it and re-add it from time to time. -->
<p class="announce">
📹 💻
<a style="font-size: 120%" href="https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPMACROSPOWER" title="This course is under a paywall on the Udemy platform. Several videos are freely available so you can judge before diving in. vindarel is (I am) the main contributor to this Cookbook."> Discover vindarel's Lisp course in videos with this September coupon.</a>
<strong>
Recently added: 18 videos on MACROS.
</strong>
<a style="font-size: 90%" href="https://github.com/vindarel/common-lisp-course-in-videos/">Learn more</a>.
</p>
<p class="announce-neutral">
📕 <a href="index.html#download-in-epub">Get the EPUB and PDF</a>
</p>
<div id="content"
<p><a href="http://www.lispworks.com/">LispWorks</a> is a Common Lisp implementation that
comes with its own Integrated Development Environment (IDE) and its share of
unique features, such as the CAPI GUI toolkit. It is <strong>proprietary</strong> and
provides a <strong>free limited version</strong>.</p>
<p>Here, we will mainly explore its IDE, asking ourselves what it can
offer to a seasoned lisper used to Emacs and Slime. The short answer
is: more graphical tools, such as an easy to use graphical stepper, a
tracer, a code coverage browser or again a class browser. Setting and
using breakpoints was easier than on Slime.</p>
<p>LispWorks also provides more integrated tools (the Process browser
lists all processes running in the Lisp image and we can
stop, break or debug them) and presents many information in the form of
graphs (for example, a graph of function calls or a graph of all the
created windows).</p>
<p><img src="assets/lispworks/two-sided-view.png" alt="LispWorks' listener and editor in the Mate desktop environment" title="The LispWorks listener an the editor in the Mate desktop environment" /></p>
<h2 id="lispworks-features">LispWorks features</h2>
<p>We can see a matrix of LispWorks features by edition and platform here: <a href="http://www.lispworks.com/products/features.html">http://www.lispworks.com/products/features.html</a>.</p>
<p>We highlight:</p>
<ul>
<li>32-bit, 64-bit and ARM support on Windows, MacOS, Linux, Solaris, FreeBSD,</li>
<li><a href="http://www.lispworks.com/documentation/lw61/CAPRM/html/capiref.htm">CAPI portable GUI toolkit</a>: provides native look-and-feel on Windows, Cocoa, GTK+ and Motif.
<ul>
<li>comes with a graphical “Interface Builder” (think QtCreator) (though not available on MacOS (nor on mobile))</li>
</ul>
</li>
<li><a href="http://www.lispworks.com/products/lw4mr.html">LispWorks for mobile runtime</a>, for Android and iOS,</li>
<li>optimized application delivery: LispWorks can use a tree shaker to
remove unused lisp code from the delivered applicatiion, thus
shipping lighter binaries than existing open-source implementations.</li>
<li>ability to deliver a dynamic library,</li>
<li>a <a href="http://www.lispworks.com/documentation/lw71/LW/html/lw-113.htm">Java interface</a>, allowing to call from Lisp to Java or the other way around,</li>
<li>an Objective-C and Cocoa interface, with drag and drop and multi-touch support,</li>
<li>a Foreign Language Interface,</li>
<li>TCP/UDP sockets with SSL &amp; IPv6 support,</li>
<li>natived threads and symmetric multiprocessing, unicode support, and all other Common Lisp features, and all other LispWorks Enterprise features.</li>
</ul>
<p>And, of course, a built-in IDE.</p>
<p>LispWorks is used in diverse areas of the industry. They maintain <a href="http://www.lispworks.com/success-stories/index.html">a list of success stories</a>. As for software that we can use ourselves, we find <a href="https://scorecloud.com/">ScoreCloud</a> amazing (a music notation software: you play an instrument, sing or whistle and it writes the music) or <a href="https://github.com/openmusic-project/openmusic/">OpenMusic</a> (opensource composition environment).</p>
<h3 id="free-edition-limitations">Free edition limitations</h3>
<p>The download instructions and the limitations are given <a href="http://www.lispworks.com/downloads/index.html">on the download page</a>.</p>
<p>The limitations are the following:</p>
<ul>
<li>There is a <strong>heap size limit</strong> which, if exceeded, causes the image to exit. A warning is provided when the limit is approached.</li>
</ul>
<p>What does it prevent us to do? As an illustration, we can not load this set of libraries together in the same image:</p>
<pre><code class="language-lisp">(ql:quickload '("alexandria" "serapeum" "bordeaux-threads" "lparallel" "dexador" "hunchentoot" "quri" "ltk" "cl-ppcre" "mito"))
</code></pre>
<ul>
<li>
<p>There is a <strong>time limit of 5 hours</strong> for each session, after which LispWorks Personal exits, possibly without saving your work or performing cleanups such as removing temporary files. You are warned after 4 hours of use.</p>
</li>
<li>
<p>It is <strong>impossible to build a binary</strong>. Indeed, the functions <a href="http://www.lispworks.com/documentation/lw71/LW/html/lw-95.htm">save-image</a>, <a href="http://www.lispworks.com/documentation/lw71/DV/html/delivery-4.htm#pgfId-852223">deliver</a> (<em>the</em> function to create a stand-alone executable), and load-all-patches are not available.</p>
</li>
<li>
<p><strong>Initialization files are not loaded</strong>. If you are used to initializing Quicklisp from your <code>~/.sbclrc</code> on Emacs, youll have to load an init file manually every time you start LispWorks (<code>(load #p"~/.your-init-file</code>)).</p>
</li>
</ul>
<p>For the record, the snippet provided by Quicklisp to put in ones startup file is the following:</p>
<pre><code class="language-lisp">;; provided you installed quicklisp in ~/quicklisp/
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp" (user-homedir-pathname))))
(when (probe-file quicklisp-init)
(load quicklisp-init)))
</code></pre>
<p>Youll have to paste it to the listener window (with the <code>C-y</code> key, y as “yank”).</p>
<ul>
<li>Layered products that are part of LispWorks Professional and Enterprise Editions (CLIM, KnowledgeWorks, Common SQL and LispWorks ORB) are not included. But <strong>we can try the CAPI toolkit</strong>.</li>
</ul>
<p>The installation process requires you to fill an HTML form to receive
a download link, then to run a first script that makes you accept the
terms and the licence, then to run a second script that installs the software.</p>
<h3 id="licencing-model">Licencing model</h3>
<p>LispWorks actually comes in four paid editions. Its all explained by themselves here: <a href="http://www.lispworks.com/products/lispworks.html">http://www.lispworks.com/products/lispworks.html</a>. In short, there is:</p>
<ul>
<li>a Hobbyist edition with <code>save-image</code> and <code>load-all-patches</code>, to apply updates of minor versions, without the obvious limitations, for non-commercial and non-academic use,</li>
<li>a HobbyistDV edition with the <code>deliver</code> function to create executables (still for non-commercial and non-academic uses),</li>
<li>a Professional edition, with the <code>deliver</code> function, for commercial and academic uses,</li>
<li>an Enterprise one, with their enterprise modules: the Common SQL interface, LispWorks ORB, KnowledgeWorks.</li>
</ul>
<p>At the time of writing, the licence of the hobbyist edition costs 750 USD, the pro version the double. They are bought for a LW version, per platform. They have no limit of time.</p>
<div class="info-box info">
<!-- if inside a <p> then bootstrap adds 10px padding to the bottom -->
<strong>NB:</strong> Please double check their upstream resources and don't hesitate to contact them.
</div>
<h2 id="lispworks-ide">LispWorks IDE</h2>
<p>The LispWorks IDE is self-contained, but it is also possible to use LispWorks-the-implementation from Emacs and Slime (see below). The IDE runs <em>inside</em> the Common Lisp image, unlike Emacs which is an external program that communicates with the Lisp image through Swank and Slime. User code runs in the same process.</p>
<h3 id="the-editor">The editor</h3>
<p>The editor offers whats expected: a TAB-completion pop-up, syntax
highlighting, Emacs-like keybindings (including the <code>M-x</code> extended
command). The menus help the discovery.</p>
<p>We personally found the editing experience a bit “raw”. For example:</p>
<ul>
<li>indention after a new line is not automatic, one has to press TAB again.</li>
<li>the auto-completion is not fuzzy.</li>
<li>there are no plugins similar to <del>Paredit</del> (there is a brand new (2021) <a href="https://github.com/g000001/lw-paredit">Paredit for LispWorks</a>) or Lispy, nor a Vim layer.</li>
</ul>
<p>We also had an issue, in that the go-to-source function bound to <code>M-.</code>
did not work out for built-in Lisp symbols. Apparently, LispWorks
doesnt provide much source code, and mostly code of the editor. Some
other commercial Lisps, like Allegro CL, provide more source code</p>
<p>The editor provides an interesting tab: Changed Definitions. It lists the functions and methods that were redefined since, at our choosing: the first edit of the session, the last save, the last compile.</p>
<p>See also:</p>
<ul>
<li>the <a href="http://www.lispworks.com/documentation/lw71/EDUG-U/html/eduser-u.htm">Editor User Guide</a>.</li>
</ul>
<h3 id="keybindings">Keybindings</h3>
<p>Most of the keybindings are similar to Emacs, but not all. Here are some differences:</p>
<ul>
<li>to <strong>compile a function</strong>, use <code>C-S-c</code> (control, shift and c), instead of C-c C-c.</li>
<li>to <strong>compile the current buffer</strong>, use <code>C-S-b</code> (instead of C-c C-k).</li>
</ul>
<p>Similar ones include:</p>
<ul>
<li><code>C-g</code> to cancel what youre doing,</li>
<li><code>C-x C-s</code> to save the current buffer,</li>
<li><code>M-w</code> and <code>C-y</code> to copy and paste,</li>
<li><code>M-b</code>, <code>M-f</code>, <code>C-a</code>, <code>C-e</code>… to move around words, to go to the beginning or the end of the line,</li>
<li><code>C-k</code> to kill until the end of the line, <code>C-w</code> to kill a selected region,</li>
<li><code>M-.</code> to find the source of a symbol,</li>
<li><code>C-x C-e</code> to evaluate the current defun,</li>
<li></li>
</ul>
<p>Some useful functions dont have a keybinding by default, for example:</p>
<!-- - delete selected text with `M-x delete-region` (or kill the region with `C-w`) -->
<ul>
<li>clear the REPL with <code>M-x Clear Listener</code></li>
<li><code>Backward Kill Line</code></li>
</ul>
<p>It is possible to use <strong>classical keybindings</strong>, à la KDE/Gnome. Go to the
Preferences menu, Environment and in the Emulation tab.</p>
<p>There is <strong>no Vim layer</strong>.</p>
<h3 id="searching-keybindings-by-name">Searching keybindings by name</h3>
<p>It is possible to search for a keybinding associated to a function, or
a function name from its keybinding, with the menu (Help -&gt; Editing -&gt;
Key to Command / Command to Key) or with <code>C-h</code> followed by a key,
as in Emacs. For example type <code>C-h k</code> then enter a keybinding to
get the command name. See more with <code>C-h ?</code>.</p>
<h3 id="tweaking-the-ide">Tweaking the IDE</h3>
<p>It is possible to change keybindings. The editors state is accessible
from the <code>editor</code> package, and the editor is built with the CAPI
framework, so we can use the <code>capi</code> interface too. Useful functions
include:</p>
<pre><code class="language-lisp">`
editor:bind-key
editor:defcommand
editor:current-point
editor:with-point ;; save point location
editor:move-point
editor:*buffer-list*
editor:*in-listener* ;; returns T when we are in the REPL
</code></pre>
<p>Heres how you can bind keys:</p>
<pre><code class="language-lisp">;; Indent new lines.
;; By default, the point is not indented after a Return.
(editor:bind-key "Indent New Line" #\Return :mode "Lisp")
;; Insert pairs.
(editor:bind-key "Insert Parentheses For Selection" #\( :mode "Lisp") ;;
(editor:bind-key "Insert Double Quotes For Selection" #\" :mode "Lisp")
</code></pre>
<p>Heres how to define a new command. We make the <code>)</code> key
to go past the next closing parenthesis.</p>
<pre><code class="language-lisp">(editor:defcommand "Move Over ()" (p)
"Move past the next close parenthesis.
Any indentation preceeding the parenthesis is deleted."
"Move past the next close parenthesis."
;; thanks to Thomas Hermann
;; https://github.com/ThomasHermann/LispWorks/blob/master/editor.lisp
(declare (ignore p))
(let ((point (editor:current-point)))
(editor:with-point ((m point))
(cond ((editor::forward-up-list m)
(editor:move-point point m)
(editor::point-before point)
(loop (editor:with-point ((back point))
(editor::back-to-indentation back)
(unless (editor:point= back point)
(return)))
(editor::delete-indentation point))
(editor::point-after point))
(t (editor:editor-error))))))
(editor:bind-key "Move Over ()" #\) :mode "Lisp")
</code></pre>
<p>And heres how you can change indentation for special forms:</p>
<pre><code class="language-lisp">(editor:setup-indent "if" 1 4 1)
</code></pre>
<p>See also:</p>
<ul>
<li>a list of LispWork keybindings: <a href="https://www.nicklevine.org/declarative/lectures/additional/key-binds.html">https://www.nicklevine.org/declarative/lectures/additional/key-binds.html</a></li>
</ul>
<h3 id="the-listener">The listener</h3>
<p>The listener is the REPL we are expecting to find, but it has a slight
difference from Slime.</p>
<p>It doesnt evaluate the input line by line or form by form, instead it
parses the input while typing. So we get some errors instantly. For
example, we type <code>(abc</code>. So far so good. Once we type a colon to get
<code>(abc:</code>, an error message is printed just above our input:</p>
<pre><code>Error while reading: Reader cannot find package ABC.
CL-USER 1 &gt; (abc:
</code></pre>
<p>Indeed, now <code>abc:</code> references a package, but such a package doesnt exist.</p>
<p>Its interactive debugger is primarily textual but you can also
interact with it with graphical elements. For example, you can use the
Abort button of the menu bar, which brings you back to the top
level. You can invoke the graphical debugger to see the stacktraces
and interact with them. See the Debugger button at the very end of the
toolbar.</p>
<p><img src="assets/lispworks/toolbar-debugger.png" alt="" /></p>
<p>If you see the name of your function in the stacktraces (you will if
you wrote and compiled your code in a file, and not directly wrote it
in the REPL), you can double-click on its name to go back to the
editor and have it highlight the part of your code that triggered the
error.</p>
<div class="info-box info">
<!-- if inside a <p> then bootstrap adds 10px padding to the bottom -->
<strong>NB:</strong> this is equivalent of pressing <code>M-v</code> in Slime.
</div>
<p>It is possible to choose the graphical debugger to appear by default, instead of the textual one.</p>
<p>The listener provides some helper commands, not unlike Slimes ones starting with a comma <code>,</code>:</p>
<pre><code>CL-USER 1 &gt; :help
:bug-form &lt;subject&gt; &amp;key &lt;filename&gt;
Print out a bug report form, optionally to a file.
:get &lt;variable&gt; &lt;command identifier&gt;
Get a previous command (found by its number or a symbol/subform within it) and put it in a variable.
:help Produce this list.
:his &amp;optional &lt;n1&gt; &lt;n2&gt;
List the command history, optionally the last n1 or range n1 to n2.
:redo &amp;optional &lt;command identifier&gt;
Redo a previous command, found by its number or a symbol/subform within it.
:use &lt;new&gt; &lt;old&gt; &amp;optional &lt;command identifier&gt;
Do variant of a previous command, replacing old symbol/subform with new symbol/subform.
</code></pre>
<h3 id="the-stepper-breakpoints">The stepper. Breakpoints.</h3>
<p>The <a href="http://www.lispworks.com/documentation/lw61/IDE-W/html/ide-w-496.htm">stepper</a> is one
of the areas where LispWorks shines.</p>
<p>When your are writing code in the editor window, you can set
breakpoints with the big red “Breakpoint” button (or by calling <code>M-x Stepper Breakpoint</code>).
This puts a red mark in your code.</p>
<p>The next time your code is executed, youll get a comprehensive Stepper pop-up window showing:</p>
<ul>
<li>your source code, with an indicator showing what expression is being evaluated</li>
<li>a lower pane with two tabs:
<ul>
<li>the backtrace, showing the intermediate variables, thus showing their evolution during the execution of the program</li>
<li>the listener, in the context of this function call, where you can evaluate expressions</li>
</ul>
</li>
<li>and the menu bar with the stepper controls: you can step into the next expression, step on the next function call, continue execution until the position of the cursor, continue the execution until the next breakpoint, etc.</li>
</ul>
<p><img src="assets/lispworks/stepper.gif" alt="" /></p>
<p>Thats not all. The non-visual, REPL-oriented stepper is also nice. It shows the forms that are being evaluated and their results.</p>
<p>In this example, we use <code>:s</code> to “step” though the current form and its subforms. We are using the usual listener, we can write any Lisp code after the prompt (the little ` -&gt; ` here), and we have access to the local variables (<code>X</code>).</p>
<pre><code class="language-lisp">CL-USER 4 &gt; (defun my-abs (x) (cond ((&gt; x 0) x) ((&lt; x 0) (- x)) (t 0)))
CL-USER 5 &gt; (step (my-abs -5))
(MY-ABS -5) -&gt; :s
-5 -&gt; :s
-5
(COND ((&gt; X 0) X) ((&lt; X 0) (- X)) (T 0)) &lt;=&gt; (IF (&gt; X 0) (PROGN X) (IF (&lt; X 0) (- X) (PROGN 0)))
;; Access to the local variables:
(IF (&gt; X 0) (PROGN X) (IF (&lt; X 0) (- X) (PROGN 0))) -&gt; (format t "Is X equal to -5? ~a~&amp;" (if (equal x -5) "yes" "no"))
Is X equal to -5? yes
(IF (&gt; X 0) (PROGN X) (IF (&lt; X 0) (- X) (PROGN 0))) -&gt; :s
(&gt; X 0) -&gt; :s
X -&gt; :s
-5
0 -&gt; :s
0
NIL
(IF (&lt; X 0) (- X) (PROGN 0)) -&gt; :s
(&lt; X 0) -&gt; :s
X -&gt; :s
-5
0 -&gt; :s
0
T
(- X) -&gt; :s
X -&gt; :s
-5
5
5
5
5
</code></pre>
<p>Here are the available stepper commands (see <code>:?</code>):</p>
<pre><code>:s Step this form and all of its subforms (optional +ve integer arg)
:st Step this form without stepping its subforms
:si Step this form without stepping its arguments if it is a function call
:su Step up out of this form without stepping its subforms
:sr Return a value to use for this form
:sq Quit from the current stepper level
:bug-form &lt;subject&gt; &amp;key &lt;filename&gt;
Print out a bug report form, optionally to a file.
:get &lt;variable&gt; &lt;command identifier&gt;
Get a previous command (found by its number or a symbol/subform within it) and put it in a variable.
:help Produce this list.
:his &amp;optional &lt;n1&gt; &lt;n2&gt;
List the command history, optionally the last n1 or range n1 to n2.
:redo &amp;optional &lt;command identifier&gt;
Redo a previous command, found by its number or a symbol/subform within it.
:use &lt;new&gt; &lt;old&gt; &amp;optional &lt;command identifier&gt;
Do variant of a previous command, replacing old symbol/subform with new symbol/subform.
</code></pre>
<h3 id="the-class-browser">The class browser</h3>
<p>The class browser allows us to examine a classs slots, parent classes, available methods, and some more.</p>
<p>Lets create a simple class:</p>
<pre><code class="language-lisp">(defclass person ()
((name :accessor name
:initarg :name
:initform "")
(lisper :accessor lisperp
:initform t)))
</code></pre>
<p>Now call the class browser:</p>
<ul>
<li>use the “Class” button from the listener,</li>
<li>or use the menu Expression -&gt; Class,</li>
<li>or put the cursor on the class and call <code>M-x Describe class</code>.</li>
</ul>
<p><img src="assets/lispworks/class-browser.png" alt="" /></p>
<p>It is composed of several panes:</p>
<ul>
<li>the <strong>class hierarchy</strong>, showing the superclasses on the left and the subclasses on the right, with their description to the bottom,</li>
<li>the <strong>superclasses viewer</strong>, in the form of a simple schema, and the same for subclasses,</li>
<li>the <strong>slots pane</strong> (the default),</li>
<li>the available <strong>initargs</strong>,</li>
<li>the existing <strong>generic functions</strong> for that class</li>
<li>and the <strong>class precedence list</strong>.</li>
</ul>
<p>The Functions pane lists all methods applicable to that class, so we can discover public methods provided by the CLOS object system: <code>initialize-instance</code>, <code>print-object</code>, <code>shared-initialize</code>, etc. We can double-click on them to go to their source. We can choose not to include the inherited methods too (see the “include inherited” checkbox).</p>
<p>Youll find buttons on the toolbar (for example, Inspect a generic
function) and more actions on the Methods menu, such as a way to see
the <strong>functions calls</strong>, a menu to <strong>undefine</strong> or <strong>trace</strong> a function.</p>
<p>See more:</p>
<ul>
<li><a href="http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u-55.htm#pgfId-871798">Chapter 8 of the documentation: the Class Browser</a></li>
</ul>
<h3 id="the-function-call-browser">The function call browser</h3>
<p>The function call browser allows us to see a graph of the callers and
the callees of a function. It provides several ways to filter the
displayed information and to further inspect the call stack.</p>
<div class="info-box info">
<!-- if inside a <p> then bootstrap adds 10px padding to the bottom -->
<strong>NB:</strong> The Slime functions to find such cross-references are <code>slime-who-[calls, references, binds, sets, depends-on, specializes, macroexpands]</code>.
</div>
<p>After loading a couple packages, heres a simple example showing who calls the <code>string-trim</code> function.</p>
<p><img src="assets/lispworks/function-call-browser.png" alt="The function call browser" /></p>
<p>It shows functions from all packages, but there is a select box to restrict it further, for example to the “current and used” or only to the current packages.</p>
<p>Double click on a function shown in the graph to go to its source. Again, as in many LispWorks views, the Function menu allows to further manipulate selected functions: trace, undefine, listen (paste the object to the Listener)…</p>
<p>The Text tab shows the same information, but textually, the callers and callees side by side.</p>
<p>We can see cross references for compiled code, and we must ensure the feature is on. When we compile code, LispWorks shows a compilation output likes this:</p>
<pre><code>;;; Safety = 3, Speed = 1, Space = 1, Float = 1, Interruptible = 1
;;; Compilation speed = 1, Debug = 2, Fixnum safety = 3
;;; Source level debugging is on
;;; Source file recording is on
;;; Cross referencing is on
</code></pre>
<p>We see that cross referencing is on. Otherwise, activate it with <code>(toggle-source-debugging t)</code>.</p>
<p>See more:</p>
<ul>
<li><a href="http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u-114.htm#pgfId-852601">Chapter 15: the function call browser</a></li>
</ul>
<h3 id="the-process-browser">The Process Browser</h3>
<p>The Process Browser shows us a list of all threads running. The input area allows to filter by name. It accepts regular expressions. Then we can stop, inspect, listen, break into these processes.</p>
<p><img src="assets/lispworks/process-browser.png" alt="&quot;The process browser&quot;" /></p>
<p>See more:</p>
<ul>
<li><a href="http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u-178.htm#pgfId-852666">Chapter 28: the Process Browser</a></li>
</ul>
<h3 id="saving-images">Saving images</h3>
<p>Saving images with LispWorks is different than with SBCL:</p>
<ul>
<li>we can save an image now, or schedule snapshots later in time</li>
<li>the new created image becomes the default core image for our LispWorks environment</li>
<li>the REPL session is saved</li>
<li>the windows configuration is saved</li>
<li>threads are saved</li>
</ul>
<p>So, effectively, we can save an image and have our development
environment back to the same state, effectively allowing to take
snapshots of our current work and to continue where we left of.</p>
<p>For example, we can start a game from the REPL, play a little bit in
its window, save an image, and when restored we will get the game and
its state back.</p>
<h3 id="misc">Misc</h3>
<p>We like the <code>Search Files</code> functionality. It is like a recursive
<code>grep</code>, but we get a typical LispWorks graphical window
that displays the results, allows to double-click on them and that offers
some more actions.</p>
<p>Last but not least, have a look at the <strong>compilation conditions
browser</strong>. LispWorks puts all warnings and errors into a special
browser when we compile a system. From now on we can work on fixing
them and see them disappear from the browser. That helps keeping track
of warnings and errors during development.</p>
<h2 id="using-lispworks-from-emacs-and-slime">Using LispWorks from Emacs and Slime</h2>
<p>To do that, you have two possibilities. The first one is to start LispWorks normally, start a Swank server and connect to it from Emacs (Swank is the backend part of Slime).</p>
<p>First, lets load the dependencies:</p>
<pre><code class="language-lisp">(ql:quickload "swank")
;; or
(load "~/.emacs.d/elpa/slime-20xx/swank-loader.lisp")
</code></pre>
<p>Start a server:</p>
<pre><code class="language-lisp">(swank:create-server :port 9876)
;; Swank started at port: 9876.
9876
</code></pre>
<p>From Emacs, run <code>M-x slime-connect</code>, choose <code>localhost</code> and <code>9876</code> for the port.</p>
<p>You should be connected. Check with: <code>(lisp-implementation-type)</code>. You are now able to use LispWorks features:</p>
<pre><code class="language-lisp">(setq button
(make-instance 'capi:push-button
:data "Button"))
(capi:contain button)
</code></pre>
<p>The second possibility is to create a non-GUI LispWorks image, with
Swank loaded, and to run this image from SLIME or SLY. For example, to
create a so-called <code>console</code> image with multiprocessing enabled:</p>
<pre><code class="language-lisp">(in-package "CL-USER")
(load-all-patches)
(save-image "~/lw-console"
:console t
:multiprocessing t
:environment nil)
</code></pre>
<p>and run LispWorks like this to create the new image ~/lw-console:</p>
<pre><code>lispworks-7-0-0-x86-linux -build /tmp/resave.lisp
</code></pre>
<p>However: <code>console</code> is implemented <strong>only for Windows and Mac</strong>.</p>
<p>See LispWorks documentation.</p>
<h2 id="see-also">See also</h2>
<ul>
<li><a href="http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u.htm">LispWorks IDE User Guide</a> (check out the sections we didnt cover)</li>
<li><a href="https://en.wikipedia.org/wiki/LispWorks">LispWorks on Wikipedia</a></li>
<li>the <a href="https://github.com/fourier/awesome-lispworks">Awesome LispWorks</a> list</li>
<li><a href="https://www.youtube.com/watch?v=nsKx40ab9SY">Real Image-based approach in Common Lisp</a> - differences between SBCL and LispWorks.</li>
</ul>
<p class="page-source">
Page source: <a href="https://github.com/LispCookbook/cl-cookbook/blob/master/lispworks.md">lispworks.md</a>
</p>
</div>
<script type="text/javascript">
// Don't write the TOC on the index.
if (window.location.pathname != "/cl-cookbook/") {
$("#toc").toc({
content: "#content", // will ignore the first h1 with the site+page title.
headings: "h1,h2,h3,h4"});
}
$("#two-cols + ul").css({
"column-count": "2",
});
$("#contributors + ul").css({
"column-count": "4",
});
</script>
<div>
<footer class="footer">
<hr/>
&copy; 2002&ndash;2023 the Common Lisp Cookbook Project
<div>
📹 Discover <a style="color: darkgrey; text-decoration: underline", href="https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358">vindarel's Lisp course on Udemy</a>
</div>
</footer>
</div>
<div id="toc-btn">T<br>O<br>C</div>
</div>
<script text="javascript">
HighlightLisp.highlight_auto({className: null});
</script>
<script type="text/javascript">
function duckSearch() {
var searchField = document.getElementById("searchField");
if (searchField && searchField.value) {
var query = escape("site:lispcookbook.github.io/cl-cookbook/ " + searchField.value);
window.location.href = "https://duckduckgo.com/?kj=b2&kf=-1&ko=1&q=" + query;
// https://duckduckgo.com/params
// kj=b2: blue header in results page
// kf=-1: no favicons
}
}
</script>
<script async defer data-domain="lispcookbook.github.io/cl-cookbook" src="https://plausible.io/js/plausible.js"></script>
</body>
</html>