Adding Textadept Support to Factor

The "Common Learning Initiative" project of #yfl has selected Factor as the language we're going to jointly learn. Factor has some nice tooling for supporting external text editors. Textadept isn't one of these. Until now.

Modifying Textadept

Before adding support for Textadept to Factor, a small alteration has to be made to the editor: adding the ability to jump to a given line in the edited file.  (This is not available natively on the Textadept command line except through the ability to insert code directly from the command line using the -e/--execute command line option.)


Thankfully adding new command line options to Textadept is a trivial matter.  args.register is a wonderful thing to provide in a text editor!  Here are the relevant contents of my init.lua file:


_M.textadept = require 'textadept'

-- Personal settings
function my_goto_line(line)
    _G.buffer:goto_line(line - 1)
args.register('-J', '--JUMP', 1, my_goto_line, 'Jump to line')


There.  I now have a -J/--JUMP option in Textadept that will jump to a given line.  Just be aware (as I initially wasn't) that Textadept processes the command line in order.  If you say textadept -J 25 my_file.txt you're going to get frustrated as it refuses to go anywhere.  What you really want to say is textadept my_file.txt -J 25.

Modifying Factor

OK, so now Textadept has the ability to jump to a given line, something that makes navigating Factor's massive library (as well as your own projects, of course!) very nice.  Now we have to add some stuff to the Factor distribution to support Textadept.


All of the editors supported out of the box in Factor can be found in <installation_root>/basis/editors/<name_of_editor>.  So, for example, from Factor's installation root we'd find support for the Vim editor in ./basis/editors/vim.  Of course putting our own stuff in the middle of Factor's own library is a Bad Idea™.  It's better to put our own projects in the work subdirectory instead.  Thus our own files are going to live in ./work/editors/textadept.  The following files are placed in that directory:

The name(s) of the author(s) of the editor support. (Michael T. Richter)
A short blurb explaining what's in the directory. (Textadept text editor integration)
I'm…really not that sure what's supposed to be in here. I just wound up copying the file from another directory (GEdit's to be precise). They all have the same contents anyway. (not loaded)
This is the actual editor support. The contents are listed below:
! Copyright (c) 2013 Michael T. Richter
! Released under the terms of WTFPL v2.0
! Consult for license details.

USING:  editors io.launcher kernel make math math.parser namespaces sequences
        system ;
IN:     editors.textadept

SINGLETON:  textadept
textadept editor-class set-global

HOOK:   find-textadept-path os ( -- path )

M:  object find-textadept-path "textadept" ;

! Example of OS-specific method
! -----------------------------
! M:  windows find-textadept-path
!         let-Windows-users-fill-this-in
!     ;

:   textadept-path  ( -- path )
        \ textadept-path get-global [
            find-textadept-path "textadept" or
        ] unless*

M:  textadept editor-command ( file line -- command )
        swap [
            textadept-path , "-f" , , "-J" , number>string ,
        ] { } make


I borrowed a technique from the jEdit support here, rather than using the simpler version for GEdit because I wanted to ensure that this would be easily-portable to other platforms.  To that end I supply the find-textadept-path hook to get OS-specific behaviour should I want it.  The first method on that hook provides a default implementation to the object class.  It just returns the string "textadept".  I currently have no other methods in place (because I don't have any other machines to test another OS on), but there's a comment showing how such a method would be coded for windows.


The real work of this file comes in the textadept-path word and the textadept method for the editor-command hook.


This word is called by the editor-command hook to get the right command to issue to the OS.  It makes use of the find-textadept-path hook we set up such that it will go to the correct one by operating system.  (Once the methods are in place for other OSes, I mean.)


This method specializes the editor-class for our purposes.  If the current editor support is for Textadept, this is the method that gets called by things like \ word edit.  Now let's assume that we're going to edit the word regoob, defined on line 25 in the file booger.factor.  The command line we want issued is textadept -f booger.factor -J 25.  As we can see the top of the stack will have the line number and the next item down will have the file name.  In the call to make, however, we need the file name first, then the line number.  We therefore swap before doing anything.  Now we build up an array of elements starting with textadept-path's return value, followed by the "-f" command line option (I like to have the files open up in their own independent window; you may wish to change this), followed by the file name (the mysterious double-comma), followed by "-J" and then followed by the line number.  What I should get, in other words, is an array that looks like this: { "textadept" "-f" "booger.factor" "-J" "25" }.  If I activate the editors.textadept vocabulary in the Listener (USE: editors.textadept) and then issue "booger.factor" 25 editor-command, it turns out that this is, in fact, exactly what I get.  And if I type \ regoob edit, Textadept opens up the file booger.factor for me and places me right on the definition of the regoob word.



Future enhancements

There are a few things that can be done to improve this editor support, of course.  We can begin with supporting Windows and MacOS, for example.  (I'll be adding Windows support before I officially submit this as a patch on the Factor repository; I can't do MacOS because I don't do Macs.)  There's another thing I'm going to want to do at some point as well.


Currently, I use the -f/--force command line option for Textadept and it's hard-coded in the editor support.  This suits my use case, but may not suit everybody else's.  I'd like to add the ability to select this so that I can use it but others don't have to.  This is probably an extra line or two.  Similarly, it would be nice if the -s/--session, -n/--nosession, and -u/--userhome options could be user-selectable, complete with the parameters for the first and last.


Watch this space.


Adding a new editor to Factor's editor support turns out to be refreshingly easy.  It's a testament to Factor's good engineering.

Filed under: , , , ,