Emacs Extensions for
GE Smallworld Magik Development
Screen-casts, tutorials, and productivity tools for Magik programmers who use Emacs. From tab-mode and code folding to the Magik Debugger and object inspector — explore features built by a developer, for developers.
Learn MoreNine screen-casts published between November 2010 and January 2011 — covering everything from ECB mode to the Tree Item GUI control. Read the story behind the project →
Get in Touch
Magik method navigation: building a minor mode
Emacs already gives Magik programmers a capable editing environment through magik-mode. A minor mode adds focused functionality without taking over the buffer’s major mode. That distinction makes minor modes ideal for navigation, inspection, folding, or debugging helpers that should feel like optional extensions to an existing Magik workflow.
Writing a minor mode for Magik in Emacs starts with an Emacs Lisp entry point, a small command set, and a clear promise about what changes. You do not need to rebuild syntax highlighting or indentation to deliver something useful. A method browser or a safer navigation command can sit comfortably beside the established editing tools.
The examples below build a method-navigation mode for Magik source files. It finds method definitions, exposes them through Imenu, and provides commands for moving between definitions. The implementation deliberately avoids production database connections and file writes, allowing it to be developed and tested with ordinary source files.
For developers in Melbourne and Sydney maintaining Smallworld systems, a compact extension can travel comfortably between workstations. It can be enabled locally, shared as an ELisp file, or packaged for a team. Australian engineering consultancies and banks often value maintainable tooling, especially when new functionality must coexist with established in-house development standards.
Choose a focused purpose
Begin with one useful behaviour rather than an ambitious framework. A good first target is moving between Magik method definitions and listing them in Imenu. Keep database debugging, compilation, production object inspection, and source folding out of the initial version. Those features involve environment-specific configuration and usually deserve separate minor modes with their own lifecycle and error handling.
Define the mode’s contract before writing its commands. Enabling it should install only the promised navigation behaviour; disabling it should restore any settings it changed. The implementation must tolerate non-Magik buffers, missing definitions, and repeated activation without modifying unrelated parts of the user’s configuration.
Build the mode and keymap
A sparse keymap keeps the extension’s commands separate from the major mode’s bindings. Emacs provides define-minor-mode for the mode itself, while the :keymap option associates the commands with that mode.
(require 'imenu)
(defvar magik-method-navigation-mode-map
(make-sparse-keymap)
"Keymap for `magik-method-navigation-mode'.")
(define-key magik-method-navigation-mode-map
(kbd "C-c M-n") #'magik-method-navigation--next)
(define-key magik-method-navigation-mode-map
(kbd "C-c M-p") #'magik-method-navigation--previous)
(define-key magik-method-navigation-mode-map
(kbd "C-c M-i") #'imenu)
(define-minor-mode magik-method-navigation-mode
"Navigate Magik method definitions without replacing `magik-mode'."
:lighter " MagikNav"
:keymap magik-method-navigation-mode-map
(if magik-method-navigation-mode
(magik-method-navigation--setup)
(magik-method-navigation--teardown)))
The mode delegates installation and removal to helper functions, which are defined later in the file. Emacs resolves those function names when the mode is enabled or a key is pressed, so their order in the source file does not affect operation. The MagikNav lighter makes the mode’s state visible in the mode line without replacing Magik’s own indicator.
Add navigation and inspection
The navigation functions use regular expressions to locate common Magik method declarations. A small helper checks the syntax state so that commented definitions do not appear as executable methods. The index function returns the structure expected by Imenu: an association list of names and buffer positions.
(defconst magik-method-navigation--method-regexp
"^[ \t]*\\(?:private[ \t]+\\)?_?method[ \t]+\\([^ \t\n()]+\\)"
"Regexp matching a Magik method definition and its name.")
(defun magik-method-navigation--code-position-p (position)
"Return non-nil when POSITION is outside a string or comment."
(let ((state (syntax-ppss position)))
(not (or (nth 3 state) (nth 4 state)))))
(defun magik-method-navigation--imenu-index ()
"Return an Imenu index of Magik method definitions."
(let ((index '()))
(save-excursion
(goto-char (point-min))
(while (re-search-forward
magik-method-navigation--method-regexp nil t)
(when (magik-method-navigation--code-position-p
(match-beginning 0))
(push (cons (match-string 1) (match-beginning 1))
index))))
(nreverse index)))
(defun magik-method-navigation--next ()
"Move to the next Magik method definition."
(interactive)
(let ((found nil))
(save-excursion
(while (and (not found)
(re-search-forward
magik-method-navigation--method-regexp nil t))
(when (magik-method-navigation--code-position-p
(match-beginning 0))
(setq found (match-beginning 1)))))
(if found
(goto-char found)
(message "No later Magik method found."))))
(defun magik-method-navigation--previous ()
"Move to the previous Magik method definition."
(interactive)
(let ((origin (point))
(previous nil))
(save-excursion
(goto-char (point-min))
(while (re-search-forward
magik-method-navigation--method-regexp nil t)
(let ((start (match-beginning 0))
(end (match-end 0)))
(when (and (< end origin)
(magik-method-navigation--code-position-p start))
(setq previous start)))
(goto-char (match-end 0))))
(if previous
(goto-char previous)
(message "No earlier Magik method found."))))
Running M-x imenu now presents an index of the discovered methods. The regular expressions cover ordinary and private method declarations, but they remain a lightweight scanner rather than a complete Magik parser. Test them against representative source before treating the index as exhaustive. Teams can compare this focused Emacs extension with Norton for Magik when deciding whether functionality should live inside Emacs or in a broader development environment.
Protect buffer-local settings
A Magik buffer may already contain a custom Imenu index or other local configuration. The setup function therefore saves the existing imenu-create-index-function before replacing it. An installation flag prevents repeated activation from overwriting the original value, and the teardown function restores it when the minor mode is disabled.
(defvar-local magik-method-navigation--saved-imenu nil)
(defvar-local magik-method-navigation--installed nil)
(defun magik-method-navigation--setup ()
"Install Magik method navigation in the current buffer."
(when (derived-mode-p 'magik-mode)
(unless magik-method-navigation--installed
(setq-local magik-method-navigation--saved-imenu
imenu-create-index-function)
(setq-local magik-method-navigation--installed t))
(setq-local imenu-create-index-function
#'magik-method-navigation--imenu-index)))
(defun magik-method-navigation--teardown ()
"Restore the Imenu setting replaced by the navigation mode."
(when magik-method-navigation--installed
(setq-local imenu-create-index-function
magik-method-navigation--saved-imenu)
(setq-local magik-method-navigation--installed nil)))
Automatic activation belongs in magik-mode-hook, where it affects Magik buffers rather than every buffer opened in Emacs. The minor mode remains buffer-local by default even when its enabling variable is globalised.
(add-hook 'magik-mode-hook #'magik-method-navigation-mode)
Avoid replacing the major mode’s keymap with use-local-map, since that would interfere with existing Magik commands. Keep this mode free of live debugger processes and database sessions. If a future extension handles customer or employee records, Australian teams must also consider the Privacy Act 1988, along with contractual and workplace controls. Source code and object contents should not leave the workstation merely because a convenient helper is available.
Test the behaviour
Use Emacs’ built-in test framework, ERT, to check the scanner against small fixtures. The first test confirms that an Imenu index contains both regular and private methods. The second checks that the next-method command reaches the expected definition.
(ert-deftest magik-method-navigation-indexes-methods ()
(with-temp-buffer
(magik-mode)
(insert "method worker.run()\n")
(insert "private method worker.reset()\n")
(should (equal
(mapcar #'car
(magik-method-navigation--imenu-index))
'("worker.run" "worker.reset")))))
(ert-deftest magik-method-navigation-moves-forward ()
(with-temp-buffer
(magik-mode)
(insert "method worker.run()\n")
(insert "method worker.stop()\n")
(goto-char (point-min))
(magik-method-navigation--next)
(should (looking-at "worker\\.run"))))
Run M-x ert, then add cases for comments, absent methods, repeated activation, and restoration of the original Imenu function. A developer in Melbourne can perform these checks on a train using a local checkout, because the tests require neither a VPN connection nor a live Smallworld session. For file edits made while refining the extension, the Undo Tree workflow provides a visual way to revisit earlier changes without abandoning the current session.
Package and use the extension
Save the implementation as magik-method-navigation.el. End the file with a provide form and the usual Emacs Lisp footer, then place the file on your load-path. During early development, loading the file directly is sufficient; a stable installation can require it from your initialisation file.
(add-to-list 'load-path "/path/to/your/elisp")
(require 'magik-method-navigation)
Enable the extension with M-x magik-method-navigation-mode, or let the magik-mode-hook activate it automatically. Use C-c M-n and C-c M-p to move between definitions, and C-c M-i to open the method index. Existing Magik highlighting, indentation, compilation, and debugging facilities remain available.
Install this example in a scratch Magik buffer, run the ERT checks, and then publish the finished package for the Magik Emacs community or your organisation’s internal tooling group.
Core Features
Tab Mode & ECB
Quick tab switching and Emacs Code Browsing mode for navigating Magik codebases efficiently.
Magik Smeller
Code analysis tool that helps identify potential issues in Magik source files.
Code Folding
Hide/Show mode for collapsing and expanding Magik code blocks to focus on what matters.
Visual Bookmarks
Quick visual bookmarks for jumping between key locations in your Smallworld session buffers.
Object Inspector
Inspect Magik objects and display them in an Emacs Deep Print buffer for detailed examination.
Magik Debugger
Set breakpoints and monitor slots and variables directly from within Emacs.
Development Tools
Direct links between Emacs and the Smallworld Development Tools application, including Click Monitor.
Screen-casts & Tutorials
Screen-cast 1: Tab Mode, ECB & More
Covers tab-mode, ECB, Magik Smeller, code folding, visual bookmarks, pragma toggling, moving code, external editor, and MS Explorer.
Screen-cast 5: Object Inspection & Deep Print
Inspect a Magik object, prompt for an expression evaluated within a Smallworld session, and display results in a Deep Print buffer.
Screen-cast 7: Magik Debugger
Useful tools for application developers: Object Inspector and Magik Debugger with breakpoints and slot/variable monitoring.
Screen-cast 9: Tree Item GUI Control
Tree Item is a GUI control providing extensive facilities for displaying lists with rows, columns, trees, and in-place editing.