CONTRIBUTING.md (12182B)
1 # The SLY Hacker's Handbook 2 3 ## Reporting bugs 4 5 The most important thing when reporting bugs is making sure that the 6 developer has a way to reproduce it. To do this, he needs to rule out 7 interference from external factors like other Emacs extensions or 8 other Lisp-side code. Here's a great example of a bug report 9 10 ``` 11 $ emacs --version 12 Emacs 24.3 13 $ sbcl --version 14 SBCL 1.2.1 15 $ cd sly 16 sly $ emacs -Q -L . -l sly-autoloads --eval '(setq inferior-lisp-program "sbcl")' -f sly 17 18 I get the REPL but when I try to X, I get Y 19 OR 20 I don't get the REPL at all because frankinbogen! 21 ``` 22 23 24 ## Coding style 25 26 This section is very empty, in the meantime try to be sensible and 27 emulate or improve on SLY's existing style. 28 29 ### Commit messages 30 31 ChangeLog files are gone! However, the syntax of ChangeLogs is very 32 useful to everybody and Emacs supports it perfectly: 33 34 * in Emacs, for every snippet that you've changed, type `C-x 4 a` (or 35 `add-change-log-entry-other-window`) 36 37 * Emacs will open up a ChangeLog buffer, but this is just a dummy 38 buffer that you can ignore. However, the content inside it should be 39 pasted (sans indentation) to the commit message. 40 41 * As an added bonus, if you are using Emacs >= 24.4 and `vc-dir` to 42 prepare your commits, Emacs does that for you automatically. 43 44 The benefits of this format are great. One can still use `M-x 45 vc-print-log` in a source file and browse through its ChangeLog 46 without the hassle of ChangeLog conflicts. 47 48 ### General philosophy 49 50 I keep a sentence of the previous Coding Guide that I like very much. 51 52 > Remember that to rewrite a program better is the sincerest form of 53 > code appreciation. When you can see a way to rewrite a part of SLY 54 > better, please do so! 55 56 57 ## Lisp code file structure 58 59 The code is organized into these files: 60 61 * `slynk/slynk-backend.lisp`: Definition of the interface to non-portable 62 features. Stand-alone. 63 64 * `slynk/backend/slynk-<cmucl|...>.lisp`: Back-end implementation 65 for a specific Common Lisp system. Uses slynk-backend.lisp. 66 67 * `slynk/slynk.lisp`: The top-level server program, built from the other 68 components. Uses `slynk-backend.lisp` as an interface to the actual 69 backends. 70 71 * `sly.el`: The Emacs front-end that the user actually interacts 72 with and that connects to the Slynk server to send expressions to, and 73 retrieve information from the running Common Lisp system. 74 75 * `contrib/sly-<extension>.el`: Elisp code for SLY extensions. 76 77 * `contrib/slynk-<extension>.lisp`: Supporting Common Lisp related 78 code for a particular extension. 79 80 81 ## SLY-Slynk RPC protocol 82 83 The info in this section would be something for a future "Slynk 84 Programmer's Guide" to be included in the regular manual or a separate 85 one. 86 87 Follows a brief description of the SLY-Slynk protocol. The protocol is 88 *s-exp messages* over *s-exp primitives* over *UTF-8* over *TCP*. 89 Let's start top-down: 90 91 ### S-exp messages 92 93 Most messages in the top group look like Lisp function calls. The 94 functions are known as "Slyfuns" and are defined with a `DEFSLYFUN` 95 operator in the `slynk-*.lisp` side. These are the "remote procedures" 96 of the RPC protocol. There must be about 100 or so of them, maybe 97 more, I haven't counted. Slyfuns appear in both Slynk's core and in 98 supporting contrib's Slynk code. 99 100 For a future reference manual, I think there has to be a way to 101 automatically harvest the `DEFSLYFUN` definitions and their 102 docstrings. 103 104 Another type of message contains calls to "channel methods". These are 105 slightly different from Slyfuns. Their return value is ignored, but 106 otherwise they also work like function calls. They're good for 107 expressing a reply-free evaluation in the context of a "channel". 108 109 These are defined with `sly-define-channel-method` and 110 `DEFINE-CHANNEL-METHOD` and on the SLY and Slynk sides, respectively. 111 112 The only use right now is in `sly-mrepl.el`, 113 114 ### S-exp primitives 115 116 This is a much smaller set of primitives, the most common is 117 `:EMACS-REX`, "rex" is for "Remote EXecution". 118 119 Informally it's saying: "here is Slyfun X's call number 3487 with 120 argumentss Y, for evaluation in thread Z" ). The asynchronous reply 121 `:RETURN`, if it ever arrives, will be "your call 3487 returned the 122 following sexp". 123 124 ```lisp 125 (:emacs-rex 126 (slynk:connection-info) 127 nil t 1) 128 (:return 129 (:ok 130 (:pid 16576 :style :spawn :encoding 131 :lisp-implementation 132 (:type "International Allegro CL Enterprise Edition" :name "allegro" :version "8.1 [Windows] (Sep 3, 2008 19:38)" :program nil) 133 :package 134 (:name "COMMON-LISP-USER" :prompt "CL-USER") 135 :version "1.0.0-alpha")) 136 1) 137 ``` 138 139 The return value, read into Elisp sexps is what is passed to the 140 callback argument to the Elisp function `sly-eval-async`. Here's the 141 way to get the PID of the underlying Slynk process. 142 143 ```elisp 144 (sly-eval-async '(slynk:connection-info) 145 (lambda (info) (plist-get info :pid))) 146 ``` 147 148 The primitives `:CHANNEL-SEND` and `:EMACS-CHANNEL-SEND` implement 149 channel methods. Channels are named by number, and normally have a 150 special serving thread in the Common Lisp implementation of 151 Slynk. Here is an extract showing the `:PROCESS`, `:WRITE-VALUES` and 152 `:PROMPT` channel methods for the REPL. 153 154 ```lisp 155 (:emacs-channel-send 1 156 (:process "(list 1 2 3)")) 157 (:channel-send 1 158 (:write-values 159 (("(1 2 3)" 2)))) 160 (:channel-send 1 161 (:prompt "COMMON-LISP-USER" "CL-USER" 0)) 162 ``` 163 164 There are also debugger-specific primitives, like `:DEBUG-ACTIVATE` 165 and `:DEBUG-RETURN`. Then there are indentation-specific primitives 166 like `:INDENTATION-UPDATE`. These could/should become 167 `:EMACS-CHANNEL-SEND`s in the future (but that would probably finally 168 break Swank compatibility). 169 170 ### UTF-8 and TCP 171 172 UTF-8 is relevant because the information in the wire are text-encoded 173 sexp's that sometimes carry strings with chunks of code, for example, 174 and these can have funky characters. 175 176 TCP is well TCP, a host and a port and reliable transfer make SLY work 177 well over any IP network. 178 179 ### Common Lisp bias 180 181 *Note: This section is very incomplete* 182 183 SLY has is primarily a Common-Lisp IDE and the supporting Slynk have 184 strong Common-lisp bias. There have been many attempts, some quite 185 successful at creating Slynk backends for other languages. 186 187 I believe that some of the Slyfuns will always be Common-Lisp specific 188 and should be marked as such. Others can perhaps be more naturally 189 adapted to other languages. 190 191 It's very important that a future reference manual have this in 192 consideration: remove the CL bias from the protocol's description, at 193 least from some of its layers, so that things like 194 [swank-js](https://github.com/swank-js/swank-js) can one day be more 195 easily implemented. 196 197 198 ## Architecture changes from SLIME to SLY 199 200 As of time of writing (SLY 1.0, SLIME 2.9) the following list 201 summarizes the main architecture differences between SLY and SLIME. If 202 it's not mentioned here, it's a safe bet that some particular 203 mechanism you're interested in stayed the same and any SLIME 204 documentation is applicable to SLY. 205 206 ### Swank is now called Slynk 207 208 SLY can be loaded alongside SLIME both in the same Emacs or Lisp 209 image. This interoperability meant that SLY's Lisp server had to be 210 renamed to "Slynk". 211 212 SLY can still speak the Swank protocol, and should be able to connect 213 to any other non-Lisp backends such as Christopher Rhodes' [swankr][4] 214 or have non-SLIME clients connect to it such as Robert Brown's 215 [swank-client][5]. 216 217 This is done via a contrib called `sly-retro` and its `slynk-retro` 218 counterpart. The contrib's code is loaded by `M-x sly` or `M-x 219 sly-connect` *on demand*, meaning that it is possible to start the 220 Slynk server without the contrib's Lisp counterpart. See the section 221 called "Slynk-loading method"" for how this works in SLY. 222 223 *If* it is loaded, `sly-retro` ensures that messages leaving SLY still 224 look like 225 226 (:emacs-rex (swank:connection-info) nil t 1) 227 228 It also ensures that incoming messages are directed to the `SLYNK` and 229 `SLYNK-BACKEND` packages. This particular redirection is done via 230 package nicknames and a trick in `lib/lisp/slynk-rpc.lisp`. The trick 231 is necessary only for the first bootstrapping messages, because on 232 startup the `sly-retro` contrib hasn't kicked in and nicknames are not 233 immediately setup. 234 235 The nicknames pose a compatibility hazard if the user tries to load 236 SLIME's Swank server into the Lisp image where Slynk is already 237 setup. Therefore, users wishing to run both servers alongside in the 238 same Lisp image must ensure that the `sly-retro` contrib is not in 239 `sly-contribs`. 240 241 (setq sly-contribs (delq 'sly-retro sly-contribs)) 242 243 [4]: https://github.com/gigamonkey/swankr 244 [5]: https://github.com/brown/swank-client 245 246 ### Slynk-loading method 247 248 In SLIME, `M-x slime` immediately tells the Lisp process started by 249 Emacs to use SLIME's own `swank-loader.lisp` program to compile and 250 load all possibly available lisp under its directory (including 251 contrib's) before the Swank server is created with 252 `SWANK:CREATE-SERVER`. 253 254 In SLY, the elisp variable `sly-init-function` is set to 255 `sly-init-using-asdf` by default, meaning that `M-x sly` will try to 256 load Slynk (the SLY equivalent to Swank) via `ASDF:LOAD-SYSTEM`. But 257 this will load only Slynk and no contribs. 258 259 Slynk contribs are also represented as ASDF systems. Internally the 260 function `sly-contrib--load-slynk-dependencies` will ask Slynk to put 261 the contrib's path to the ASDF load path. The `SLYNK:REQUIRE-MODULE` 262 abstraction will then call `ASDF:LOAD-SYSTEM`. 263 264 In SLY, a contrib's associated Slynk modules is loaded on demand, not 265 forced on the user's Lisp run-time. 266 267 This also allows the developer to write completely independent 268 third-party extensions to SLY, with both Emacs and Lisp parts. See the 269 URL http://github.com/joaotavora/sly-hello-world for an example 270 extension. 271 272 Additionally, if SLY detects that ASDF is not available in the Lisp 273 run-time, it will fallback to the old `slynk-loader.lisp` mechanism, 274 which has also been revised to support the previous two use cases. Any 275 of the two methods is transparent from Emacs's perspective. 276 277 ### mREPL 278 279 `slime-mrepl` is an experimental SLIME contrib that inspired 280 `sly-mrepl`, which is a much enhanced version of it and the default 281 REPL for SLY. The main difference to the popular `slime-repl` contrib 282 is that `sly-mrepl` is based on Emacs's own `comint.el` so that that 283 SLY does not need to worry about functionality like history navigation 284 and persistent history, which are consistent with other Emacs modes 285 based on `comint.el`. 286 287 `sly-mrepl` allows multiple REPLs through the use of channels, which 288 are abstraction pioneered in SLIME. Channels are like separate 289 mailboxes in the Lisp run-time, and it's slightly different from the 290 regular `:emacs-rex` RPC calls in that they directly invoke a remote 291 method but expect no reply. 292 293 In `slynk-mrepl.lisp`, the `mrepl` class multiple inherits from 294 `slynk:channel` and `slynk:listener`. The first takes care of 295 channel-based communication and the second has the REPL-specific 296 context. 297 298 See the section on the "RPC protocl" and switch to the `*sly-events*` 299 buffer to see what's going on. 300 301 ### Display-related code 302 303 SLIME's age and historical compatibility with XEmacs means it 304 reinvented (and possibly invented) many buffer/window/display managing 305 techniques that are available today in GNU Emacs's core. Interactive 306 buttons, display-related and completion-code have all been pruned as 307 much as possible and now reuse Emacs' own libraries. 308 309 Hopefully this will make SLY's code focus on SLY's "business logic" 310 and easier to read. 311 312 ### Channels 313 314 TODO 315 316 ### Listeners 317 318 TODO 319 320 321 ## Pull requests 322 323 * Read [how to properly contribute to open source projects on Github][1]. 324 * Use a topic branch to easily amend a pull request later, if necessary. 325 * Commit messages should use the syntax of GNU ChangeLog entries. 326 * Open a [pull request][2] that relates to *only* one subject with a 327 clear title and description in grammatically correct, complete 328 sentences. 329 330 [1]: http://gun.io/blog/how-to-github-fork-branch-and-pull-request 331 [2]: https://help.github.com/articles/using-pull-requests 332 [3]: http://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html#Style-of-Change-Logs