Thursday, July 24, 2008

Creating a python mode for emacs from scratch

One of many ideas that has been rattling around my brain for a while is to *really* learn emacslisp. At the minimum I'd like to just understand the tools that are available. And beyond that I'd like to contribute back a little. But that's just not going to happen until I have a deeper understanding of the monster that is emacs and emacslisp.

Rather than just goof around with toy projects I thought I'd dive right in and try to grok something that is very useful to me and something I'd like to understand even better. A good candidate for this is python.el. I use it everyday, I feel I could be using more of it and I'd love to help make it better.

My plan plan, then, is to recreate this python-mode from scratch. Of course I'll be cheating mightily by just cutting and pasting code, the game is that I can only cut and paste things that I understand what they do and how they fit into the big picture (and it has to work at each stage).

So, I start with a blank file and I'm not done until it's an exact match to the original. The original (which came with my emacs for windows install "This is GNU Emacs 22.0.990.1 (i386-mingw-nt6.0.6000) of 2007-05-23 on LENNART-69DE564 (patched)") is python.el (CVS for those of you playing the home versoin of the game.

Here is a brief outline of what I'll need to address

126 matches for "^(def" in buffer: python.el
75:(defgroup python nil
90:(defvar python-font-lock-keywords
114:(defconst python-font-lock-syntactic-keywords
131:(defun python-quote-syntax (n)
195:(defvar python-mode-map
280:(defvar python-mode-syntax-table
301:(defsubst python-in-string/comment ()
306:(defconst python-space-backslash-table
312:(defun python-skip-comments/blanks (&optional backward)
330:(defun python-backslash-continuation-line-p ()
335:(defun python-continuation-line-p ()
350:(defun python-comment-line-p ()
358:(defun python-blank-line-p ()
364:(defun python-beginning-of-string ()
371:(defun python-open-block-statement-p (&optional bos)
380:(defun python-close-block-statement-p (&optional bos)
391:(defun python-outdent-p ()
406:(defcustom python-indent 4
413:(defcustom python-guess-indent t
418:(defcustom python-indent-string-contents t
429:(defcustom python-honour-comment-indentation nil
437:(defcustom python-continuation-offset 4
444:(defun python-guess-indent ()
475:(defvar python-indent-list nil
478:(defvar python-indent-list-length nil
481:(defvar python-indent-index nil
484:(defun python-calculate-indentation ()
594:(defun python-initial-text ()
605:(defconst python-block-pairs
614:(defun python-first-word ()
620:(defun python-indentation-levels ()
681:(defun python-indent-line-1 (&optional leave)
700:(defun python-indent-line ()
724:(defun python-indent-region (start end)
739:(defun python-block-end-p ()
754:(defun python-beginning-of-defun ()
786:(defun python-end-of-defun ()
832:(defun python-beginning-of-statement ()
849:(defun python-skip-out (&optional forward syntax)
871:(defun python-end-of-statement ()
897:(defun python-previous-statement (&optional count)
912:(defun python-next-statement (&optional count)
928:(defun python-beginning-of-block (&optional arg)
969:(defun python-end-of-block (&optional arg)
1003:(defvar python-recursing)
1004:(defun python-imenu-create-index ()
1062:(defun python-electric-colon (arg)
1076:(defun python-backspace (arg)
1104:(defcustom python-check-command "pychecker --stdlib"
1109:(defvar python-saved-check-command nil
1113:(defun python-check (command)
1136:(defcustom python-python-command "python"
1144:(defcustom python-jython-command "jython"
1150:(defvar python-command python-python-command
1156:(defvar python-buffer nil
1175:(defconst python-compilation-regexp-alist
1188:(defvar inferior-python-mode-map
1202:(defvar inferior-python-mode-syntax-table
1214:(define-derived-mode inferior-python-mode comint-mode "Inferior Python"
1245:(defcustom inferior-python-filter-regexp "\\`\\s-*\\S-?\\S-?\\s-*\\'"
1251:(defun python-input-filter (str)
1257:(defun python-args-to-list (string)
1266:(defvar python-preoutput-result nil
1269:(defvar python-preoutput-leftover nil)
1270:(defvar python-preoutput-skip-next-prompt nil)
1274:(defun python-preoutput-filter (s)
1324:(defun run-python (&optional cmd noshow new)
1385:(defun python-send-command (command)
1403:(defun python-send-region (start end)
1439:(defun python-send-string (string)
1451:(defun python-send-buffer ()
1458:(defun python-send-defun ()
1464:(defun python-switch-to-python (eob-p)
1473:(defun python-send-region-and-go (start end)
1480:(defcustom python-source-modes '(python-mode jython-mode)
1488:(defvar python-prev-dir/file nil
1494:(defun python-load-file (file-name)
1517:(defun python-proc ()
1528:(defun python-set-proc ()
1541:(defconst python-dotty-syntax-table
1549:(defvar view-return-to-alist)
1552:(defvar python-imports) ; forward declaration
1557:(defun python-describe-symbol (symbol)
1599:(defun python-send-receive (string)
1614:(defun python-eldoc-function ()
1643:(defun python-after-info-look ()
1695:(defcustom python-jython-packages '("java" "javax" "org" "com")
1704:(defun python-maybe-jython ()
1731:(defun python-fill-paragraph (&optional justify)
1774:(defun python-shift-left (start end &optional count)
1798:(defun python-shift-right (start end &optional count)
1811:(defun python-outline-level ()
1818:(defun python-current-defun ()
1835:(defun python-mark-block ()
1851:(defvar python-imports nil
1861:(defun python-find-imports ()
1896:(defun python-symbol-completions (symbol)
1912:(defun python-partial-symbol ()
1923:(defun python-complete-symbol ()
1957:(defun python-try-complete (old)
1979:(defun python-module-path (module)
1988:(defcustom python-use-skeletons nil
1995:(defvar python-skeletons nil
1999:(defvar python-mode-abbrev-table nil
2002:(define-abbrev-table 'python-mode-abbrev-table ())
2007:(defmacro def-python-skeleton (name &rest elements)
2025:(def-python-skeleton if
2035:(define-skeleton python-else
2043:(def-python-skeleton while
2049:(def-python-skeleton for
2055:(def-python-skeleton try/except
2066:(define-skeleton python-target
2070:(def-python-skeleton try/finally
2077:(def-python-skeleton def
2084:(def-python-skeleton class
2094:(defvar python-default-template "if"
2098:(defun python-expand-template (name)
2122:(defun python-setup-brm ()
2166:(defvar outline-heading-end-regexp)
2167:(defvar eldoc-documentation-function)
2170:(defun python-abbrev-pc-hook ()
2175:(defvar python-abbrev-syntax-table
2179:(defun python-pea-hook ()
2185:(defvar python-mode-running) ;Dynamically scoped var.
2188:(define-derived-mode python-mode fundamental-mode "Python"
2297:(define-derived-mode jython-mode python-mode "Jython"

Damn! That looks like a bit of work. OK, this mode isn't going to understand itself, let's get cracking. Tune in soon for the first of (potentially) many installments.

No comments: