Defining colorizer modes in @script

31 views
Skip to first unread message

Brian Theado

unread,
Nov 27, 2013, 2:51:02 PM11/27/13
to leo-editor
I wrote a colorizer for myself which highlights timestamp strings in
the form of '2013/11/27 14:05:29 -' at the start of lines.

Leo's colorizer class was hard-coded to recognize mode definitions
only in Leo's mode directory. My mode is not very general purpose and
so doesn't really belong in that directory.

I wanted to be able to define my mode in an @script node, so I
refactored some of the colorizer code in order to make it possible. I
pulled out into a separate method the part of the jeditColorizer
init_mode method which didn't care about how the mode got loaded. Now
my @script code can call that new method.

My refactoring seems a little clumsy to me...I don't understand how
all the ivars in that class are used and settled for the small change
I made. Edward, feel free to polish.

There is still another class which also assumes colorizer modes must
have a corresponding file in the modes directory. I didn't figure out
how to resolve that issue and settled for a very ugly hack of
monkey-patching that method with hard-coded recognition of my mode.
The c.frame.body.colorizer.isValidLanguage method is the one I
monkey-patched. Anyone with ideas on how I should fix this without
monkey-patching, let me know.

With my latest bzr checkin, the following in an @script node works to
colorize my date strings (includes the monkey-patched method). I don't
recall now why I named my mode 'sol':

<?xml version="1.0" encoding="utf-8"?>
<!-- Created by Leo (http://leoeditor.com/leo_toc.html) -->
<?xml-stylesheet ekr_test?>
<leo_file xmlns:leo="http://www.leo-editor.org/2011/leo" >
<leo_header file_format="2"/>
<vnodes>
<v t="btheado.20131127134049.2386" a="E"><vh>sol colorizing</vh>
<v t="btheado.20131127134049.2387" a="E"><vh>class sol</vh>
<v t="btheado.20111207194929.3751"><vh>timestamp colorizer rules</vh></v>
</v>
<v t="btheado.20131127134049.2389"><vh>load rule</vh></v>
</v>
</vnodes>
<tnodes>
<t tx="btheado.20111207194929.3751">@language python
# Leo colorizer control file for sol mode.
# This file is in the public domain.

# This mode colorizes timestamp strings like
# '2011/12/04 20:31:16 -' which appear at the
# start of a line

properties = { }

# Attributes dict for solt_main ruleset.
sol_main_attributes_dict = {
"default": "null",
"digit_re": "",
"escape": "",
"highlight_digits": "false",
"ignore_case": "false",
"no_word_sep": "",
}

# Dictionary of attributes dictionaries for sol mode.
attributesDictDict = {
"sol_main": sol_main_attributes_dict,
}

# Keywords dict for sol_main ruleset.
sol_main_keywords_dict = {}

# Dictionary of keywords dictionaries for sol mode.
keywordsDictDict = {
"sol_main": sol_main_keywords_dict,
}

# Rules for sol_main ruleset.
import leo.core.leoGlobals as g

def sol_rule0(colorer, s, i):
#re = r"\d{8} \d\d:\d\d:\d\d -"
re = r"\d\d\d\d/?\d\d/?\d\d \d\d:\d\d:\d\d -"
m = colorer.match_seq_regexp(s, i, kind="keyword2", regexp=re,
at_line_start=True, at_whitespace_end=False,
at_word_start=False, delegate="")
return m

# Rules dict for sol_main ruleset. All of the possible first
# matching characters for each rule must have a mapping enumerated
# here. The 'sol_rule0' for example has \d at the front of the
# regexp and so any numeral can match
rulesDict1 = {
"0": [sol_rule0,],
"1": [sol_rule0,],
"2": [sol_rule0,],
"3": [sol_rule0,],
"4": [sol_rule0,],
"5": [sol_rule0,],
"6": [sol_rule0,],
"7": [sol_rule0,],
"8": [sol_rule0,],
"9": [sol_rule0,],
}

# x.rulesDictDict for sol mode.
rulesDictDict = {
"sol_main": rulesDict1,
}

# Import dict for sol mode.
importDict = {}
</t>
<t tx="btheado.20131127134049.2386">@others

# Monkey-patch this method to also recognize the
# 'sol' mode as I didn't figure out how to fix this
# in general
def isValidLanguage (self,language):
fn = g.os_path_join(g.app.loadDir,'..','modes','%s.py' % (language))
return g.os_path_exists(fn) or language == 'sol'

from types import MethodType
c.frame.body.colorizer.isValidLanguage = \
MethodType(isValidLanguage, c.frame.body.colorizer)
</t>
<t tx="btheado.20131127134049.2387">class sol:
@others</t>
<t tx="btheado.20131127134049.2389">c.frame.body.colorizer.highlighter.colorer.init_mode_from_module('sol',
sol)</t>
</tnodes>
</leo_file>

Edward K. Ream

unread,
Dec 5, 2013, 10:58:07 AM12/5/13
to leo-editor
On Wed, Nov 27, 2013 at 1:51 PM, Brian Theado <brian....@gmail.com> wrote:

I wanted to be able to define my mode in an @script node, so I
refactored some of the colorizer code in order to make it possible. I
pulled out into a separate method the part of the jeditColorizer
init_mode method which didn't care about how the mode got loaded. Now
my @script code can call that new method.

​Looks reasonable to me.  ​
 

My refactoring seems a little clumsy to me...I don't understand how
all the ivars in that class are used and settled for the small change
I made. Edward, feel free to polish.

​There has never been anything elegant about this code.  The word "polish" does not apply ;-)
 
There is still another class which also assumes colorizer modes must
have a corresponding file in the modes directory. I didn't figure out
how to resolve that issue and settled for a very ugly hack of
monkey-patching that method with hard-coded recognition of my mode.
The c.frame.body.colorizer.isValidLanguage method is the one I
monkey-patched. Anyone with ideas on how I should fix this without
monkey-patching, let me know.

​Just commit a generalization of the monkey-patched version.​
 
​ And then document it, please.

The idea is to add a keyword argument.  Something like this (not tested):

    def isValidLanguage (self,language,path=None):
        if path is None:
            path = g.os_path_join(g.app.loadDir,'..','modes')
        fn = g.os_path_finalize_join(path,'%s.py' % (language))
        return g.os_path_exists(fn)

I use this keyword arg trick all the time to add special cases to methods.

HTH.

Edward
Reply all
Reply to author
Forward
0 new messages