[Mac] Python mode for Alpha editor

Howard Oakley Howard at quercus.demon.co.uk
Fri Sep 17 15:05:07 EDT 1999


Gentlepersons,

I looked in vain for a Python mode for the wonderful (if Tcl-based!) text
editor, Alpha. I could not find any. Here, below, is an Alpha mode file for
Python, which makes the Alpha text editor much more usable for editing
Python code. Please feel free to post it anywhere that you feel
appropriate. The code works fine here, but is kludgy and largely borrowed
from other Tcl mode files - I could hardly claim any sort of copyright
anyway!

I am also sending it to Pete Keleher, the author of Alpha, and Jack Jansen.

Howard.
--------------cut here-----------------
# (auto-install)
#############################################################################
# pythonMode.tcl
#  Howard Oakley, EHN & DIJ Oakley
#  howard at quercus.demon.co.uk
#
# Description:
#	This auto-installing file implements a simple mode for editing
#	Python using Alpha. It has been tested with Alpha version 7.2.
#	The features of this mode include:
#	syntax colouring - comments in red, strings (some) in green,
#		keywords in blue, and colons (a Python particular) in magenta
#	easy production of comment boxes etc.
#	def and class marking - automatically generated marks (M popup) give
#		the function name first, and then the class (if any), whilst class
#		definitions give the class name twice; the {} popup takes
#		you to class definitions
#	automatic indentation - given the importance of this in Python control
#		structures, this was an essential, and is accomplished
#		using tabs in syntactic context.
#	The code below is a cobbling together of code stolen from other sources.
#	Whilst the fine code of the original sources is reliable, there are
#	all sorts of nasty kludges which I have used to get it to do what
#	I needed. Tcl purists who can improve on it are invited to do so:
#	please e-mail your corrections to me so that I can maintain this.
#	My thanks and apologies to those from whom I have stolen code.
# Version: 1.0 dated 17 Sep 1999 [or if you prefer it, 1999-09-17].
#############################################################################
alpha::mode Pyth 1.0 dummyPyth {*.py} {electricBraces electricTab
electricReturn}

newPref	v leftFillColumn {1} Pyth
newPref	v wordBreak {\w+} Pyth
newPref	f wordWrap {0} Pyth
newPref	v funcExpr {^[ \t]*(def|class)[ \t]+([A-Za-z0-9_]+)} Pyth
newPref	v parseExpr {^[ \t]*([A-Za-z0-9_]*)} Pyth
newPref	v wordBreakPreface {\W} Pyth
newPref	f autoMark 0 Pyth

proc dummyPyth {} {}

# I extend the range of keywords a little, to include some type conversions
# and other important items

set pythKeyWords {
	access and break class continue def del elif else
	except exec finally for from global if import in
	is lambda not or pass print raise return self try while 
	= < > <= >= + * - / != <> % | ^ &
	len min max ~ abs int long float complex divmod pow
	list map tuple eval string repr assert
}

regModeKeywords -e {#} -s green -c red -i : -I magenta -k blue Pyth
$pythKeyWords
unset pythKeyWords

hook::register saveHook modified "Pyth"
#================================================================================
# for Tcl 8.0 compatibility, hopefully
namespace eval Pyth {}
#================================================================================

proc dummyPyth {} {}

# for easy production of comment boxes etc.

set commentCharacters(Pyth:General) "\#"
set commentCharacters(Pyth:Paragraph) [list "#----" "#----" "#"]
set commentCharacters(Pyth:Box) [list "#" 2 "#" 2 "#" 3]

# the mark routine, which has to append the class name *if* the definition
is
# part of a class definition, but reset the empty class name if it is not,
# i.e. there is no leading whitespace before the 'def'
# - this therefore builds the M popup menu.

proc Pyth::MarkFile {} {
	global PythmodeVars
	set pos [minPos]
	set classnom ""
	
	while {![catch {search -s -f 1 -r 1 -m 0 -i 1 $PythmodeVars(funcExpr)
$pos} res]} {
		set start [lindex $res 0]
		set end [pos::math [lindex $res 1] + 1]
		set text [getText $start $end]
		
		if {[regexp	-indices {(class)[ \t]+([a-zA-Z0-9_]+)} $text dummy
dummy0	pname]} {
		    set	i1 [expr [lindex $pname	0]	+ $start]
		    set	i2	[expr [lindex $pname 1]	+ $start + 1]
# this is the start of a class definition, so save the class name
		    set	classnom  [getText $i1 $i2]
		} else {
		    if {$pos > [minPos]} {
			set pp [pos::math $start - 1]
			set pq [pos::math $start + 1]
			set pr [getText $pp $pq]
			if {![regexp {[ \t]+} $pr]} {
# this is a standalone def, therefore reset the class name to an empty
string
			    set classnom ""
			}
		    }
		}
				
		if {[regexp	-indices {(def|class)[ \t]+([a-zA-Z0-9_]+)} $text dummy
dummy0	pname]}	{
			set	i1 [expr [lindex $pname	0]	+ $start]
			set	i2	[expr [lindex $pname 1]	+ $start + 1]
			set	word  [getText $i1 $i2]
			set	tmp	[concat	$i1	$i2]
# assemble the marker name with the def element first, followed by any
class name
			set ol_word [ join [concat $word " " $classnom ""] ]
			set inds($ol_word) $tmp
		}

	
		set pos $end
	}
	if {[info exists inds]} {
      foreach f [lsort -ignore [array names inds]] {
			set res $inds($f)
			setNamedMark $f [lineStart [lindex $res 0]] [lindex $res 0] [lindex $res
1]
		}
	}
}

# this builds the {} menu along similar lines, but this time with just
class definitions
proc Pyth::parseFuncs {} {
	global PythmodeVars
	set pos [minPos]
	
	while {![catch {search -s -f 1 -r 1 -m 0 -i 1 $PythmodeVars(funcExpr)
$pos} res]} {
		set start [lindex $res 0]
		set end [pos::math [lindex $res 1] + 1]
		set text [getText $start $end]
		
		if {[regexp	-indices {(class)[ \t]+([a-zA-Z0-9_]+)} $text dummy
dummy0	pname]} {
		    set	i1 [expr [lindex $pname	0]	+ $start]
		    set	i2	[expr [lindex $pname 1]	+ $start + 1]
		    set	word  [getText $i1 $i2]
		    set	tmp	[concat	$i1	$i2]
		    set inds($word) $tmp
		}
		set pos $end
	}
	set rtnRes {}
    
	if {[info exists inds]} {
	    foreach f [lsort -ignore [array names inds]] {
		set next [nextLineStart $inds($f)]
		lappend rtnRes $f $next
	    }
	}
	return $rtnRes 
}

proc Pyth::indentLine {} {
    # get details of current line
    set beg [lineStart [getPos]]
    set text [getText $beg [nextLineStart $beg]]
    regexp "^\[ \t\]*" $text white
    set len [string length $white]
    set epos [pos::math $beg + $len]
    
    # Find last previous non-comment line and get its leading whitespace
    set pos $beg
    while 1 {
	if {[catch {search -s -f 0 -r 1 -i 0 -m 0 "^\[ \t\]*\[^ \t\r\n\]"
[pos::math $pos - 1]} lst]} {
	    # search failed at top of file
	    set line "#"
	    set lwhite 0
	    break
	}
	if {![catch {text::inCommentBlock [lindex $lst 0]} res]} {
	    set pos [lindex $res 0]
	} else {
	    set line [getText [lindex $lst 0] [pos::math [nextLineStart [lindex
$lst 0]] - 1]]
	    set lwhite [posX [pos::math [lindex $lst 1] - 1]]	
	    break
	}
    }
# we need (syntactically) to increase the tabs by 1, so first do this using
# spaces, and then convert the spaces to a tab. This is not elegant, but it
works!   
    if {[regexp ":\[ \t\]*$" $line]} {
	getWinInfo a
	set ps $a(tabsize)
	incr lwhite $ps
    }
    set lwhite [text::indentOf $lwhite]
    if {$white != $lwhite} {
	replaceText $beg $epos $lwhite
	select $beg [$beg + [string length $lwhite]]
	spacesToTabs
    }
    goto [pos::math $beg + [string length $lwhite]]
}
------------end---------------







More information about the Python-list mailing list