//[of]:description //[c]The main application window (includes menu + all opened windows) //[cf] //[of]:license //[c]Code Browser - a folding text editor for programmers //[c]Copyright (C) 2003-07 Marc Kerbiquet //[c] //[c]This program is free software; you can redistribute it and/or modify //[c]it under the terms of the GNU General Public License as published by //[c]the Free Software Foundation; either version 2 of the License, or //[c](at your option) any later version. //[c] //[c]This program is distributed in the hope that it will be useful, //[c]but WITHOUT ANY WARRANTY; without even the implied warranty of //[c]MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //[c]GNU General Public License for more details. //[c] //[c]You should have received a copy of the GNU General Public License //[c]along with this program; if not, write to the Free Software //[c]Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //[cf] //[of]:imports import "base/types" import "base/memory-allocator" import "base/memory-buffer" import "text/string" import "text/string-buffer" import "text/vector-of-strings" import "text/array-of-strings" import "file/file" import "net/uri" import "swift" //[c] import "utilities/file-utils" import "utilities/text-utils" import "utilities/word-dictionary" import "editor/text-model" import "editor/text-view" import "editor/tree-view" //[c] import "../res/cb" import "application/strings-en" import "application/code-browser-application" import "application/text-file" import "code-browser-window" import "multi-pane-window" //[cf] //[of]:aliases //[c]Shorter alias private typedef frame = code browser frame box private typedef application = code browser application //[cf] //[c] //[of]:user tool command struct user tool command frame: frame tool: user tool command: command end //[cf] //[of]:search process //[of]:definition struct search process // the file database file database : file database // search parameters data : find data // output object output : text object root : text object output to close : text object // number of found items count : dword // number of items that could not be replaced because of read only not replaced count : dword // list of already scanned folders (prevent infinite loops) folders : local vector // the last folder containing a match last reported folder : text object // the last file containing a match last reported file : text file // files and directory to process pending files: local array of strings pending directories: local array of strings // Group result by files ? group by files: bool end //[cf] //[of]:action //[of]:find in directory (patterns, dirname) func find in directory ( p: search process, patterns: list of filemasks) : void if ~ is empty (pending files (p)) find in file (p, pending files (p) [0]) remove (pending files (p), 0) elsif ~ is empty (pending directories (p)) def dirname = pending directories (p) [0] def t := string buffer def d := directory (dirname) each file (d) ? name concat path (t, dirname, name) if match (patterns, name) add (pending files (p), as string (t)) end end if subdirectories (data (p)) each directory (d) ? name concat path (t, dirname, name) add (pending directories (p), as string (t)) end end remove (pending directories (p), 0) release (d) release (t) end end //[c] func concat path (t: string buffer, dirname: string, name: string) remove all (t) t << dirname if ~ ends with (dirname, path separator) t << path separator end t << name end //[cf] //[of]:find in file (filename) func find in file (p: search process, filename: string) def data = data (p) def fd = file database (p) // Test if the file can be closed after search def to close = false if ~ follow links (data) to close = is nil (find text file (fd, filename)) end // open the file def text file = open (fd, filename) if is nil (text file) return end output to close (p) = nil find all (p, text file) def output = output to close (p) if not nil (output) // a valid text object must end with an empty comment line add (output, new empty comment line) end if to close && ~ is modified (text file) close (fd, text file) last reported file (p) = nil end end //[cf] //[of]:find all (file) //[c] public func find all ( process: search process, text file: text file) : void find all ( process, text file, root folder (text file), 0) end //[cf] //[of]:find all (file, folder, absolute line number) //[c] public func find all ( process: search process, text file: text file, folder: text object, aln: line number) : void find all ( process, text file, folder, aln, first line (folder), 0, last line (folder), -1) end //[cf] //[of]:find all (file, folder, absolute line number, first line, fist col, last line, last col) public func find all ( process: search process, text file: text file, folder: text object, aln: line number, first line: text line, first column: int, last line: text line, last column: int) : void def data = data (process) //[c] //[c] If 'follow links' option is activated, we must mark scanned folder //[c] and check for loops. //[c] if follow links (data) if contains (folders (process), folder) return end add (folders (process), folder) end //[c] //[c] Scan the lines //[c] def t := temp string buffer def path := temp string buffer def text line = first line def line column = first column repeat def buf = display text (text line) def col = first column first column = 0 def limit = search limit (data, ((text line == last line) && last column <> -1) -> last column, size (buf)) while col < limit if match (data, buf, col) > 0 // increase counter ++ count (process) // report the file only once if group by files (process) && text file <> last reported file (process) // remember it last reported file (process) = text file remove all (t) append basename (text file, t) def output = new text object (empty string, as string (t)) def line = new folder line (output, root (process)) add (root (process), line) output (process) = output output to close (process) = output end // report the location only once if folder <> last reported folder (process) // remember it last reported folder (process) = folder // append an empty line as separator add (output (process), new empty comment line) // append a description of the location remove all (t) if ~ group by files (process) append basename (text file, t) if root folder (text file) <> folder t << " - " end end if root folder (text file) <> folder append description (folder, t) end if not empty (t) t << $: add (output (process), new text line (t, lt comment)) end end def p = skip blanks (buf) def uri := convert filename to uri (filename (text file)) remove all (path) path << uri << "?aln=" << (aln+1) release (uri) def link = new link object (empty string, p, as string (path)) add (output (process), new link line (link)) if replace (data) if ~ is read only (text file) def res := replace (data, folder, text line, col) col = col (res) - 1 // the last line must also be fixed up if last line == text line last line = line (res) end text line = line (res) buf = buf (text line) limit = search limit (data, size (text line)) else // not replaced because read only not replaced count (process) += 1 end else // report only once per line break end end ++ col end if is link (text line) && follow links (data) def location := open target location (file database (process), text file, text line) def child text file = text file (location) def child folder = folder (location) if not nil (child folder) def new aln = absolute line number (child folder, first line (child folder)) find all (process, child text file, child folder, new aln) end ++ aln elsif is folder (text line) def child folder = text object (text line) if subfolders (data) find all (process, text file, child folder, aln+1) end aln += 2 + number of lines (child folder) else ++ aln end if text line == last line break end text line = next (text line) end release (path) release (t) end //[cf] //[cf] //[of]:testing //[of]:is done func is done (p: search process) return is empty (pending files (p)) && is empty (pending directories (p)) end //[cf] //[cf] //[cf] //[of]:command box //[of]:description //[c]Container for embedded dialogs //[cf] //[of]:definition public struct command box : local container box private a child has focus: bool private empty: bool private default button: button private cancel button: button private original default button: button end //[c] public struct command box class : local container box class // empty end //[cf] //[of]:instance creation //[of]:new command box public func new command box (parent: box) equ s = sizeof local command box def b = allocate memory (s): command box initialize (b, parent) return b end //[cf] //[of]:initializer struct i command box: local i box; end func new (i: i command box, parent: box, c: [] object) return new command box (parent) end public equ command box = const i command box (^new (i command box, box, [] object)) //[cf] //[cf] //[of]:accessing //[of]:set default button //[c]Sets the default button (permanent) //[c] public func set default button (m: command box, b: button) original default button (m) = b set current default button (m, b) end //[cf] //[of]:set cancel button //[c]Configures the cancel button //[c] public func set cancel button (m: command box, b: button) cancel button (m) = b end //[cf] //[cf] //[of]:visibility //[of]:show child //[c]Shows the child box //[c] public func show child ( m: command box, default: button, cancel: button) delete (first child (m)) def child = first child (m) activate (child) invalidate min size (m) set default button (m, default) set cancel button (m, cancel) // This is a workaround to a bug with the Windows 'edit' control: // if the text is set before the control is correctly sized, the text // will be scrolled. // // Since the set-focus command do a select all, the validate // size force the select all to show the complete text // without scrolling. validate size (m) set focus (child) empty (m) = false end //[cf] //[of]:hide child //[c]Hide (destroy) the child box //[c] public func hide child (m: command box) def cancel = cancel button (m) if not nil (cancel) click (cancel) end end //[cf] //[cf] //[of]:testing //[of]:is empty //[c]Returns true if the container is empty //[c] public equ is empty (m: command box) = empty (m) //[cf] //[cf] //[c] //[of]:restricted //[of]:command box class public func command box class def c = the command box class if ~ cb initialized cb initialized = true c . copy (container box class) c . compute min size = ^actual compute min size (command box) c . on size = ^adjust to parent (box) c . on focus = ^focus to first visible (box, event) c . adjust = ^adjust to parent (box) c . on child event = ^handle child event (command box, box, event) end return c end private def cb initialized = false private def the command box class : local command box class //[cf] //[of]:initialize public func initialize (m: command box, parent: box) initialize (super (m), parent) class (m) = command box class a child has focus (m) = false original default button (m) = nil default button (m) = nil cancel button (m) = nil show blank (m) end //[cf] //[of]:actual compute min size public func actual compute min size (m: command box) def w = 1 def h = 1 def c = first child (m) if not nil (c) w = max (w, min width (c)) h = max (h, min height (c)) end set min size (m, w, h) end //[cf] //[of]:handle child event public func handle child event (m: command box, src: box, evt: event) def t = type (evt) if t == blur event type a child has focus (m) = false elsif t == focus event type a child has focus (m) = true if src <> default button (m) def button = as button (src) if is nil (button) button = original default button (m) end set current default button (m, button) end elsif t == key down event type equ e = evt: key event def button = default button (m) if not nil (button) && key (e) == VK RETURN click (button) return true end button = cancel button (m) if not nil (button) && key (e) == VK ESCAPE click (button) return true end end return handle child event (super (m), src, evt) end //[cf] //[cf] //[of]:private //[of]:set current default button //[c]Sets the current default button (temporary) //[c] private func set current default button (m: command box, b: button) if b <> default button (m) if not nil (default button (m)) set default (default button (m), false) end default button (m) = b if not nil (b) set default (b, true) end end end //[cf] //[of]:show blank func show blank (m: command box) def blank = new blank box (m, 1) empty (m) = true activate (blank) invalidate min size (m) end //[cf] //[of]:close public func close (m: command box) if is empty (m) return end def has focus = a child has focus (m) original default button (m) = nil default button (m) = nil cancel button (m) = nil invalidate min size (m) delete (first child (m)) show blank (m) // if the command box has the focus: transfer it to the first successor if has focus set focus (m) end end //[cf] //[cf] //[cf] //[of]:dialogs //[of]:goto line //[of]:definition private enum goto line component line number box = ok cancel max local folder box gl cmax end //[c] public struct goto line frame : local container box private components : [gl cmax] object line number : line number local folder : bool command box : command box frame : frame end //[c] public struct goto line frame class : local container box class end //[cf] //[of]:instance creation //[of]:new goto line frame public func new goto line frame (parent: command box, frame: frame) def f = allocate memory (sizeof local goto line frame): goto line frame initialize (f, parent, frame) return f end //[cf] //[c] //[cf] //[of]:restricted //[of]:goto line frame class public func goto line frame class def c = the goto line frame class if ~ gl initialized gl initialized = true copy (c, container box class) release (c) = ^actual release (goto line frame) on child event (c) = ^handle child event (goto line frame, box, event) on size (c) = ^handle single child size (box) compute min size (c) = ^actual compute signle child min size (box) end return c end private def gl initialized = false private def the goto line frame class: local goto line frame class //[cf] //[of]:initialize public func initialize (f: goto line frame, parent: command box, frame: frame) initialize (super (f), parent) class (f) = goto line frame class new (props grid, f, components (f)) command box (f) = parent frame (f) = frame line number (f) = 0 local folder (f) = false set text (line number box (f), "1") end //[c] //[c]Resources: //[c] def props grid := grid box ( 2, default inner margin, const [] int (1, 0, -1), const [] int (1, -1), const grid cells ( grid cell (grid box ( 0, default inner margin, const [] int (0, 1, 0, -1), const [] int (0, 1, -1), const grid cells ( grid cell (label box (str line number label), 0, 0), grid cell (line number box << edit box, 1, 0), grid cell (local folder box << check box (str local folder), 2, 0), nil) ), 0, 0), grid cell (ok cancel buttons 2, 1, 0), nil) ) //[cf] //[of]:handle child event public func handle child event (f: goto line frame, src: box, evt: event) if type (evt) == click event type if src == ok button (f) save data (f) def win = active window (frame (f)) if not nil (win) def line number = line number (f) : int if local folder (f) goto local line (win, line number) else goto absolute line (win, line number) end close (command box (f)) end return true elsif src == cancel button (f) save data (f) close (command box (f)) return true end end return handle child event (super (f), src, evt) end //[cf] //[of]:actual release public func actual release (m: goto line frame) actual release (super (m)) end //[cf] //[cf] //[of]:private //[of]:save data func save data (f: goto line frame) def s = text (line number box (f)) line number (f) = max (0, decimal to integer (s) - 1) local folder (f) = value (local folder box (f)) end //[cf] //[c] //[of]:ok button public equ ok button (m: goto line frame) = components (m) [ok button] : button //[cf] //[of]:cancel button public equ cancel button (m: goto line frame) = components (m) [cancel button] : button //[cf] //[of]:line number box private equ line number box (m: goto line frame) = components (m) [line number box] : edit box //[cf] //[of]:local folder box private equ local folder box (m: goto line frame) = components (m) [local folder box] : check box //[cf] //[cf] //[cf] //[of]:find //[of]:definition public enum find mode find iterative find incremental find all find in files end //[c] private enum find component find what label find what edit replace with edit find where combo match case check box match whole word check box regular expression check box subfolders check box follow links check box start button mark all button replace button replace all button cancel find button directory label directory edit patterns label patterns edit subdirectories check box find cmax end //[c] public struct find box : local container box command box: command box frame: frame components: [find cmax] object data : local find data persist data: find data is replace: bool mode: find mode incremental: bool // this flag prevent doing incremental search during initialization: // the value changed event is ignored in the initialization phase initializing: bool end //[c] public struct find box class : local container box class end //[cf] //[of]:instance creation //[of]:new find box public func new find box ( parent: command box, frame: frame, persist data: find data, find mode: find mode, is replace: bool) def b = allocate memory (sizeof local find box): find box initialize (b, parent, frame, persist data, find mode, is replace) return b end //[cf] //[cf] //[of]:restricted //[of]:class public func find box class def c = the find box class if ~ find initialized find initialized = true copy (c, container box class) on child event (c) = ^handle child event (find box, box, event) release (c) = ^actual release (find box) on size (c) = ^handle single child size (box) compute min size (c) = ^actual compute signle child min size (box) end return c end private def find initialized = false private def the find box class: local find box class //[cf] //[of]:initialize public func initialize ( m: find box, parent: command box, frame: frame, persist data: find data, mode: find mode, is replace: bool) initialize (super (m), parent) class (m) = find box class initializing (m) = true def incremental = false if mode == find incremental mode = find iterative incremental = true end def res : i box switch mode case find iterative res = (is replace -> replace resource, find resource) case find all res = (is replace -> replace all resource, find all resource) else res = (is replace -> replace in files resource, find in files resource) end new (res, m, components (m)) persist data (m) = persist data frame (m) = frame command box (m) = parent is replace (m) = is replace mode (m) = mode incremental (m) = incremental def data = data (m) initialize (data, find data (frame)) get selection (frame, data) set replace (data, is replace) set mnemonic box (find what label (m), find what edit (m)) set text (find what edit (m), search string (data)) set list (find what edit (m), search history (data)) def v := vector of strings (4) switch mode case find iterative add (v, str file scope caption) add (v, str folder scope caption) set list (find where combo (m), v, 0) set index (find where combo (m), scope (data): int) case find all add (v, str current file caption) add (v, str current folder caption) add (v, str current selection caption) set list (find where combo (m), v, 0) set index (find where combo (m), start (data): int) end release (v) set checked (match case check box (m), is case sensitive (data)) set checked (match whole word check box (m), match whole word (data)) set checked (regular expression check box (m), regular expression (data)) if mode <> find iterative set checked (subfolders check box (m), subfolders (data)) set checked (follow links check box (m), follow links (data)) end if mode == find in files set text (patterns edit (m), patterns (data)) set list (patterns edit (m), patterns history (data)) set text (directory edit (m), directory (data)) set checked (subdirectories check box (m), subdirectories (data)) end if is replace set text (replace with edit (m), replace string (data)) set list (replace with edit (m), replace history (data)) end update button enabling (m) initializing (m) = false if incremental incremental search (m, true) end end //[c] //[c]Resources: //[of]: find def find resource := grid box ( 2, default inner margin, const [] int (0, 1, 0, 0, -1), const [] int (0, 0, 1, -1), const grid cells ( grid cell (find what label << label box (str find what caption), 0, 0), grid cell (find what edit << drop down edit box, 1, 0), grid cell (label box (str find where caption), 0, 1), grid cell (find where combo << drop down list box , 1, 1), grid cell (options, 2, 0, 1, 3), grid cell (buttons, 3, 0, 1, 3), nil) ) //[cf] //[of]: replace def replace resource := grid box ( 2, default inner margin, const [] int (0, 1, 0, 0, -1), const [] int (0, 0, 0, 1, -1), const grid cells ( grid cell (find what label << label box (str find what caption), 0, 0), grid cell (find what edit << drop down edit box, 1, 0), grid cell (label box (str replace with caption), 0, 1), grid cell (replace with edit << drop down edit box , 1, 1), grid cell (label box (str find where caption), 0, 2), grid cell (find where combo << drop down list box , 1, 2), grid cell (blank box, 0, 3, 2, 1), grid cell (options, 2, 0, 1, 4), grid cell (replace buttons, 3, 0, 1, 4), nil) ) //[c] def replace buttons := grid box ( 0, default inner margin, const [] int (1, -1), const [] int (0, 0, 0, 1, 0, -1), const grid cells ( grid cell (start button << button (str find next caption), 0, 0), grid cell (replace button << button (str replace caption), 0, 1), grid cell (replace all button << button (str replace all caption), 0, 2), grid cell (cancel find button << button (str cancel caption), 0, 4), nil) ) //[cf] //[of]: find all def find all resource := grid box ( 2, default inner margin, const [] int (0, 1, 0, 0, -1), const [] int (0, 0, 1, -1), const grid cells ( grid cell (find what label << label box (str find what caption), 0, 0), grid cell (find what edit << drop down edit box, 1, 0), grid cell (label box (str start caption), 0, 1), grid cell (find where combo << drop down list box , 1, 1), grid cell (options all, 2, 0, 1, 3), grid cell (find all buttons, 3, 0, 1, 3), nil) ) //[cf] //[of]: find in files def find in files resource := grid box ( 2, default inner margin, const [] int (0, 1, 0, 0, -1), const [] int (0, 0, 0, 0, 1, -1), const grid cells ( grid cell (find what label << label box (str find what caption), 0, 0), grid cell (find what edit << drop down edit box, 1, 0), grid cell (patterns label << label box (str patterns caption), 0, 1), grid cell (patterns edit << drop down edit box , 1, 1), grid cell (directory label << label box (str find directory caption), 0, 2), grid cell (directory edit << directory box , 1, 2), grid cell (subdirectories check box << check box (str subdirectories caption), 1, 3), grid cell (options all, 2, 0, 1, 5), grid cell (find all buttons, 3, 0, 1, 5), nil) ) //[cf] //[of]: replace all def replace all resource := grid box ( 2, default inner margin, const [] int (0, 1, 0, 0, -1), const [] int (0, 0, 0, 1, -1), const grid cells ( grid cell (find what label << label box (str find what caption), 0, 0), grid cell (find what edit << drop down edit box, 1, 0), grid cell (label box (str replace with caption), 0, 1), grid cell (replace with edit << drop down edit box, 1, 1), grid cell (label box (str start caption), 0, 2), grid cell (find where combo << drop down list box , 1, 2), grid cell (options all, 2, 0, 1, 4), grid cell (replace all buttons, 3, 0, 1, 4), nil) ) //[cf] //[of]: replace in files def replace in files resource := grid box ( 2, default inner margin, const [] int (0, 1, 0, 0, -1), const [] int (0, 0, 0, 0, 0, 1, -1), const grid cells ( grid cell (find what label << label box (str find what caption), 0, 0), grid cell (find what edit << drop down edit box, 1, 0), grid cell (label box (str replace with caption), 0, 1), grid cell (replace with edit << drop down edit box, 1, 1), grid cell (patterns label << label box (str patterns caption), 0, 2), grid cell (patterns edit << drop down edit box , 1, 2), grid cell (directory label << label box (str find directory caption), 0, 3), grid cell (directory edit << directory box , 1, 3), grid cell (subdirectories check box << check box (str subdirectories caption), 1, 4), grid cell (options all, 2, 0, 1, 6), grid cell (replace all buttons, 3, 0, 1, 6), nil) ) //[cf] //[c] def buttons := grid box ( 0, default inner margin, const [] int (1, -1), const [] int (0, 0, 1, 0, -1), const grid cells ( grid cell (start button << button (str find next caption), 0, 0), grid cell (mark all button << button (str mark all caption), 0, 1), grid cell (cancel find button << button (str cancel caption), 0, 3), nil) ) //[c] def options := grid box ( 0, default inner margin, const [] int (1, -1), const [] int (0, 0, 0, 1, -1), const grid cells ( grid cell (match case check box << check box (str match case caption), 0, 0), grid cell (match whole word check box << check box (str match whole word caption), 0, 1), grid cell (regular expression check box << check box (str regular expression caption), 0, 2), nil) ) //[c] def options all := grid box ( 0, default inner margin, const [] int (1, -1), const [] int (0, 0, 0, 0, 0, 0, 1, -1), const grid cells ( grid cell (subfolders check box << check box (str subfolders caption), 0, 0), grid cell (follow links check box << check box (str follow links caption), 0, 1), grid cell (match case check box << check box (str match case caption), 0, 3), grid cell (match whole word check box << check box (str match whole word caption), 0, 4), grid cell (regular expression check box << check box (str regular expression caption), 0, 5), nil) ) //[c] def find all buttons := grid box ( 0, default inner margin, const [] int (1, -1), const [] int (0, 1, 0, -1), const grid cells ( grid cell (start button << button (str find all caption), 0, 0), grid cell (cancel find button << button (str cancel caption), 0, 2), nil) ) //[c] def replace all buttons := grid box ( 0, default inner margin, const [] int (1, -1), const [] int (0, 1, 0, -1), const grid cells ( grid cell (start button << button (str replace all caption), 0, 0), grid cell (cancel find button << button (str cancel caption), 0, 2), nil) ) //[cf] //[of]:actual release public func actual release (m: find box) actual release (super (m)) release (data (m)) end //[cf] //[of]:handle child event public func handle child event (m: find box, src: box, evt: event) def type = type (evt) if type == click event type if src == start button (m) start (m) return true elsif src == mark all button (m) mark all (m) return true elsif src == replace button (m) replace (m) return true elsif src == replace all button (m) replace all (m) return true elsif src == cancel find button (m) cancel (m) return true end elsif type == value changed event type if ~ initializing (m) update button enabling (m) if incremental (m) incremental search (m, true) end end elsif type == key down event type equ e = evt: key event def key = key (e) if status (e) == ALT if is replace (m) if key == $R : int set focus (replace button (m)) replace (m) return true elsif key == $A : int set focus (replace all button (m)) replace all (m) return true end end if key == $N : int set focus (find what edit (m)) return true elsif key == $C : int set focus (match case check box (m)) click (match case check box (m)) return true elsif key == $W : int set focus (match whole word check box (m)) click (match whole word check box (m)) return true elsif key == $E : int set focus (regular expression check box (m)) click (regular expression check box (m)) return true end if mode (m) <> find iterative if key == $A : int set focus (start button (m)) start (m) return true elsif key == $F : int set focus (subfolders check box (m)) click (subfolders check box (m)) return true elsif key == $L : int set focus (follow links check box (m)) click (follow links check box (m)) return true end elsif ~ is replace (m) if key == $A : int set focus (mark all button (m)) mark all (m) return true end end end end return handle child event (super (m), src, evt) end //[cf] //[cf] //[of]:private //[of]:start private func start (m: find box) if is empty (text (find what edit (m))) return end def window = active window (frame (m)) if is nil (window) return end update find data structure (m) switch mode (m) case find iterative do find (m) case find all start find (frame (m), false) close (command box (m)) else start find (frame (m), true) close (command box (m)) end end //[cf] //[of]:mark all private func mark all (m: find box) if is empty (text (find what edit (m))) return end def window = active window (frame (m)) if is nil (window) return end update find data structure (m) do mark all (frame (m)) do find (m) end //[cf] //[of]:replace private func replace (m: find box) if is empty (text (find what edit (m))) return end def window = active window (frame (m)) if is nil (window) return end update find data structure (m) def file = current text file (window) if is read only (file) return end if selection matches (window, data (m)) do replace (m) end do find (m) end //[cf] //[of]:replace all private func replace all (m: find box) if is empty (text (find what edit (m))) return end def window = active window (frame (m)) if is nil (window) return end update find data structure (m) def file = current text file (window) if is read only (file) return end def data = data (m) def n = replace all (window, data) if n > 0 def s := temp string buffer printf (s, str replace count, n) message box (m, as string (s), app title, mb ok) release (s) else show not found message box (m) end end //[cf] //[of]:cancel private func cancel (m: find box) close (command box (m)) end //[cf] //[c] //[of]:do find //[c]Perform a find from the dialog box (without closing it) //[c] private func do find (m: find box) if incremental (m) incremental search (m, false) return end def found = find (frame (m), false) if ~ found show not found message box (m) // found and not in replace mode: close the dialog elsif ~ is replace (m) close (command box (m)) end end //[cf] //[of]:do replace //[c]Perform a replace from the dialog box //[c] private func do replace (m: find box) def window = active window (frame (m)) if is nil (window) return end replace selection (window, replace string of last match (data (m))) end //[cf] //[c] //[of]:incremental search private func incremental search (m: find box, first: bool) def has find = not empty (text (find what edit (m))) def window = active window (frame (m)) if has find && not nil (window) update find data structure (m) find (frame (m), first) end end //[cf] //[of]:show not found message box func show not found message box (m: find box) message box (frame (m), search string not found, app title, mb ok) end //[cf] //[of]:update button enabling public func update button enabling (m: find box) def has find = not empty (text (find what edit (m))) set enable (start button (m), has find) if mode (m) == find iterative if is replace (m) set enable (replace button (m), has find) set enable (replace all button (m), has find) else set enable (mark all button (m), has find) end end end //[cf] //[of]:update find data structure //[c]The find data structure is updated according to control's values //[c] private func update find data structure (m: find box) def data = data (m) def s = text (find what edit (m)) set search string (data, s) if ~ incremental (m) add to find history (data, s) end set direction (data, find next) switch mode (m) case find iterative set scope (data, index (find where combo (m)): find scope) case find all set start (data, index (find where combo (m)): find scope) end set case sensitive (data, is checked (match case check box (m))) match whole word (data) = is checked (match whole word check box (m)) regular expression (data) = is checked (regular expression check box (m)) if mode (m) <> find iterative set subfolders (data, is checked (subfolders check box (m))) set follow links (data, is checked (follow links check box (m))) end if mode (m) == find in files def p = text (patterns edit (m)) set patterns (data, p) add to patterns history (data, p) set directory (data, text (directory edit (m))) set subdirectories (data, is checked (subdirectories check box (m))) end if is replace (m) def r = text (replace with edit (m)) set replace string (data, r) add to replace history (data, r) end compile (data) set (persist data (m), data) end //[cf] //[c] //[of]:start button //[c]This is the main start action button. //[c]It can be 'Find next' 'Find All' or 'Replace All'. //[c] private equ start button (m: find box) = components (m) [start button]: button //[cf] //[of]:mark all button private equ mark all button (m: find box) = components (m) [mark all button]: button //[cf] //[of]:replace button private func replace button (m: find box) return (is replace (m) -> components (m) [replace button]: button, nil) end //[cf] //[of]:replace all button private func replace all button (m: find box) return (is replace (m) -> components (m) [replace all button]: button, nil) end //[cf] //[of]:cancel find button public equ cancel find button (m: find box) = components (m) [cancel find button]: button //[cf] //[of]:find what label private equ find what label (m: find box) = components (m) [find what label] : label box //[cf] //[of]:find what edit private equ find what edit (m: find box) = components (m) [find what edit] : drop down edit box //[cf] //[of]:replace with edit private equ replace with edit (m: find box) = components (m) [replace with edit] : drop down edit box //[cf] //[of]:find where combo private equ find where combo (m: find box) = components (m) [find where combo] : drop down list box //[cf] //[of]:match case check box private equ match case check box (m: find box) = components (m) [match case check box] : check box //[cf] //[of]:match whole word check box private equ match whole word check box (m: find box) = components (m) [match whole word check box] : check box //[cf] //[of]:regular expression check box private equ regular expression check box (m: find box) = components (m) [regular expression check box] : check box //[cf] //[c] //[of]:subfolders check box private equ subfolders check box (m: find box) = components (m) [subfolders check box] : check box //[cf] //[of]:follow links check box private equ follow links check box (m: find box) = components (m) [follow links check box] : check box //[cf] //[c] //[of]:directory label private equ directory label (m: find box) = components (m) [directory label] : edit box //[cf] //[of]:patterns label private equ patterns label (m: find box) = components (m) [patterns label] : edit box //[cf] //[of]:directory edit private equ directory edit (m: find box) = components (m) [directory edit] : directory box //[cf] //[of]:patterns edit private equ patterns edit (m: find box) = components (m) [patterns edit] : drop down edit box //[cf] //[of]:subdirectories check box private equ subdirectories check box (m: find box) = components (m) [subdirectories check box] : check box //[cf] //[cf] //[cf] //[of]:edit arguments //[of]:definition private enum edit arguments frame component arguments edit = ok cancel max arguments label edit arg cmax end //[c] public struct edit arguments frame : local container box components : [edit arg cmax] object frame: frame command box: command box directory: string tool: user tool end //[c] public struct edit arguments frame class : local container box class end //[cf] //[of]:instance creation //[of]:new edit arguments frame public func new edit arguments frame ( parent: command box, frame: frame, tool: user tool, title: string, arguments: string, directory: string) def f = allocate memory (sizeof local edit arguments frame): edit arguments frame initialize (f, parent, frame, tool, title, arguments, directory) return f end //[cf] //[cf] //[of]:restricted //[of]:edit arguments frame class public func edit arguments frame class def c = the edit arguments frame class if ~ edit arguments initialized edit arguments initialized = true copy (c, container box class) release (c) = ^actual release (edit arguments frame) on child event (c) = ^handle child event (edit arguments frame, box, event) on size (c) = ^handle single child size (box) compute min size (c) = ^actual compute signle child min size (box) end return c end private def edit arguments initialized = false private def the edit arguments frame class: local edit arguments frame class //[cf] //[of]:initialize public func initialize ( m: edit arguments frame, parent: command box, frame: frame, tool: user tool, title: string, arguments: string, directory: string) initialize (super (m), parent) class (m) = edit arguments frame class new (edit arguments props grid, m, components (m)) directory (m) = new string (directory) frame (m) = frame command box (m) = parent tool (m) = tool // setup label with title def t := temp string buffer printf (t, str edit arguments, title) set text (arguments label (m), as string (t)) release (t) //invalidate min size (parent) //validate size (frame) set text (arguments box (m), arguments) end //[c] //[c]Resources: //[c] def edit arguments props grid := grid box ( 2, default inner margin, const [] int (1, 0, -1), const [] int (1, -1), const grid cells ( grid cell (grid box ( 0, default inner margin, const [] int (0, 1, -1), const [] int (0, 1, -1), const grid cells ( grid cell (arguments label << label box, 0, 0), grid cell (arguments edit << edit box, 1, 0), nil) ), 0, 0), grid cell (ok cancel buttons 2, 1, 0), nil) ) //[cf] //[of]:handle child event public func handle child event (f: edit arguments frame, src: box, evt: event) if type (evt) == click event type if src == ok button (f) def arguments = text (arguments box (f)) run tool (frame (f), tool (f), arguments, directory (f)) tool (f) = nil // the tool must not be deleted anymore by the dialog close (command box (f)) return true elsif src == cancel button (f) close (command box (f)) return true end end return handle child event (super (f), src, evt) end //[cf] //[of]:actual release public func actual release (m: edit arguments frame) actual release (super (m)) delete (directory (m)) if not nil (tool (m)) delete (tool (m)) end end //[cf] //[c] //[cf] //[of]:private private equ ok button (f: edit arguments frame) = components (f) [ok button] : button private equ cancel button (f: edit arguments frame) = components (f) [cancel button] : button private equ arguments box (f: edit arguments frame) = components (f) [arguments edit] : edit box private equ arguments label (f: edit arguments frame) = components (f) [arguments label] : label box //[cf] //[cf] //[of]:edit properties //[of]:definition private enum edit properties frame components id edit = ok cancel max id label name edit name label path edit path label properties apply button properties close button properties cmax end //[c] public struct edit properties frame : local container box components : [properties cmax] object command box: command box frame: frame text: text object line: text line text listener: local text listener ignore event: bool end //[c] public struct edit properties frame class : local container box class end //[cf] //[of]:instance creation //[of]:new edit link frame public func new edit properties frame (parent: command box, frame: frame) def f = allocate memory (sizeof local edit properties frame): edit properties frame initialize (f, parent, frame) return f end //[cf] //[cf] //[of]:accessing //[of]:set line func set line (m: edit properties frame, text: text object, line: text line) if line == line (m) return end unregister folder listener (m) text (m) = text line (m) = line register folder listener (m) if not nil (line) def file = find text file (file database (frame (m)), text) if is nil (file) return end def read only = is read only (file) if is folder (line) def folder = text object (line) set text (id box (m), id (folder)) def t := temp string buffer escape string (t, title (folder)) set text (name box (m), as string (t)) release (t) set text (path box (m), empty string) select all (name box (m)) update enabling (m, false, true, read only) return elsif is link (line) def link = link object (line) set text (id box (m), id (link)) def t := temp string buffer escape string (t, title (link)) set text (name box (m), as string (t)) release (t) set text (path box (m), path (link)) select all (name box (m)) update enabling (m, true, true, read only) return end end set text (id box (m), empty string) set text (name box (m), empty string) set text (path box (m), empty string) update enabling (m, false, false, false) end //[cf] //[cf] //[of]:restricted //[of]:edit link frame class public func edit properties frame class def c = the edit properties frame class if ~ edit properties initialized edit properties initialized = true copy (c, container box class) release (c) = ^actual release (edit properties frame) on child event (c) = ^handle child event (edit properties frame, box, event) on size (c) = ^handle single child size (box) compute min size (c) = ^actual compute signle child min size (box) end return c end //[c] private def edit properties initialized = false private def the edit properties frame class: local edit properties frame class //[cf] //[of]:initialize public func initialize ( m: edit properties frame, parent: command box, frame: frame) initialize (super (m), parent) class (m) = edit properties frame class new (edit properties grid, m, components (m)) command box (m) = parent frame (m) = frame text (m) = nil line (m) = nil ignore event (m) = false def tl = text listener (m) recipient (tl) = m text changed (tl) = ^ignore replace event (object, text object, replace text event) prop changed (tl) = ^handle prop changed (edit properties frame, text object, replace prop event) group changed (tl) = ^ignore group event (object, text object, bool) destroyed (tl) = ^handle destroyed (edit properties frame, text object) marker added (tl) = ^ignore marker (object, text object, text marker) marker removed (tl) = ^ignore marker (object, text object, text marker) end //[c] //[c]Resources: //[c] def edit properties grid := grid box ( 2, default inner margin, const [] int (1, 0, -1), const [] int (1, -1), const grid cells ( grid cell (grid box ( 0, default inner margin, const [] int (0, 1, -1), const [] int (0, 0, 0, 1, -1), const grid cells ( grid cell (name label << label box (str folder name), 0, 0), grid cell (name edit << edit box, 1, 0), grid cell (id label << label box (str folder id), 0, 1), grid cell (id edit << edit box, 1, 1), grid cell (path label << label box (str link path), 0, 2), grid cell (path edit << edit box, 1, 2), nil) ), 0, 0), grid cell (edit properties buttons, 1, 0), nil) ) //[c] def edit properties buttons := grid box ( 0, default inner margin, const [] int (1, -1), const [] int (0, 1, 0, -1), const grid cells ( grid cell (properties apply button << button (str apply caption), 0, 0), grid cell (properties close button << button (str close caption), 0, 2), nil) ) //[cf] //[of]:handle child event public func handle child event (m: edit properties frame, src: box, evt: event) def type = type (evt) if type == click event type if src == apply button (m) apply (m) close (command box (m)) return true elsif src == close button (m) close (command box (m)) return true end elsif type == value changed event type enable (apply button (m)) end return handle child event (super (m), src, evt) end //[cf] //[of]:actual release public func actual release (m: edit properties frame) actual release (super (m)) unregister folder listener (m) end //[cf] //[c] //[of]:handle prop changed func handle prop changed (m: edit properties frame, text: text object, e: replace prop event) // another line if line (m) <> line object (e) return end // changed being made by myself if ignore event (m) return end set line (m, text (m), line (m)) end //[cf] //[of]:handle destroyed func handle destroyed (m: edit properties frame, text: text object) set line (m, nil, nil) end //[cf] //[cf] //[of]:private //[of]:apply func apply (m: edit properties frame) ignore event (m) = true def id = text (id box (m)) def t := temp string buffer unescape string (t, text (name box (m))) def name = as string (t) def path = text (path box (m)) def line = line (m) def text = text (m) if not nil (line) if is folder (line) set folder properties (text, line, id, name) elsif is link (line) set link properties (text, line, id, name, path) end end release (t) ignore event (m) = false end //[cf] //[of]:update enabling func update enabling (m: edit properties frame, path enable: bool, enable: bool, read only: bool) set enable (id label (m), enable) set enable (id box (m), enable) set enable (name label (m), enable) set enable (name box (m), enable) set enable (path label (m), path enable) set enable (path box (m), path enable) disable (apply button (m)) set read only (id box (m), read only) set read only (name box (m), read only) set read only (path box (m), read only) // hack - if disabling, force the focus to be reassigned if ~ enable set focus (frame (m)) end end //[cf] //[of]:register folder listener private func register folder listener (m: edit properties frame) def text = text (m) if is nil (text) return end add listener (text, text listener (m)) end //[cf] //[of]:unregister folder listener private func unregister folder listener (m: edit properties frame) def text = text (m) if is nil (text) return end remove listener (text, text listener (m)) end //[cf] //[of]:components private equ apply button (f: edit properties frame) = components (f) [properties apply button] : button private equ close button (f: edit properties frame) = components (f) [properties close button] : button public equ id box (f: edit properties frame) = components (f) [id edit] : edit box public equ id label (f: edit properties frame) = components (f) [id label] : label box public equ name box (f: edit properties frame) = components (f) [name edit] : edit box public equ name label (f: edit properties frame) = components (f) [name label] : label box public equ path box (f: edit properties frame) = components (f) [path edit] : edit box public equ path label (f: edit properties frame) = components (f) [path label] : label box //[cf] //[cf] //[cf] //[c] //[of]:create link //[of]:definition private enum create link frame components create link id = ok cancel max create link name create link path create link cmax end //[c] public struct create link frame : local dialog box components : [create link cmax] object new id : string new name : string new path : string end //[c] public struct create link frame class : local dialog box class end //[cf] //[of]:instance creation //[of]:new edit link frame public func new create link frame (parent: box, style: box style, ro: bool) def f = allocate memory (sizeof local create link frame): create link frame initialize (f, parent, style, ro) return f end //[cf] //[cf] //[of]:accessing //[of]:id public func id (m: create link frame) return new id (m) end //[cf] //[of]:name public func name (m: create link frame) return new name (m) end //[cf] //[of]:path public func path (m: create link frame) return new path (m) end //[cf] //[c] //[of]:set id public func set id (m: create link frame, s: string) set text (id box (m), s) end //[cf] //[of]:set name public func set name (m: create link frame, s: string) def t := temp string buffer escape string (t, s) set text (name box (m), as string (t)) release (t) end //[cf] //[of]:set path public func set path (m: create link frame, s: string) set text (path box (m), s) end //[cf] //[cf] //[of]:restricted //[of]:edit link frame class public func create link frame class def c = the create link frame class if ~ create link initialized create link initialized = true copy (c, dialog box class) release (c) = ^actual release (create link frame) on child event (c) = ^handle child event (create link frame, box, event) end return c end //[c] private def create link initialized = false private def the create link frame class: local create link frame class //[cf] //[of]:initialize public func initialize (f: create link frame, parent: box, style: box style, ro: bool) initialize (f, parent, style, create link frame class, cancel button, create link res, components (f)) new id (f) = empty string new name (f) = empty string new path (f) = empty string set read only (id box (f), ro) set read only (name box (f), ro) set read only (path box (f), ro) end //[c] //[c]Resources: //[c] def create link res := dialog box resources ( create link props grid, str create link title, 400, 120, ok button, cancel button) //[c] def create link props grid := grid box ( 5, default inner margin, const [] int (1, -1), const [] int (1, 0, -1), const grid cells ( grid cell (grid box ( 0, default inner margin, const [] int (0, 1, -1), const [] int (0, 0, 0, 1, -1), const grid cells ( grid cell (label box (str folder name), 0, 0), grid cell (create link name << edit box, 1, 0), grid cell (label box (str folder id), 0, 1), grid cell (create link id << edit box, 1, 1), grid cell (label box (str link path), 0, 2), grid cell (create link path << edit box, 1, 2), grid cell (blank box, 0, 3, 2, 1), nil) ), 0, 0), grid cell (ok cancel buttons, 0, 1), nil) ) //[cf] //[of]:handle child event public func handle child event (f: create link frame, src: box, evt: event) if type (evt) == click event type if src == ok button (f) // copy string since the control is going to // be unbound on close(f) def t := temp string buffer unescape string (t, text (name box (f))) new name (f) = new string (t) release (t) new path (f) = new string (text (path box (f))) new id (f) = new string (text (id box (f))) close (f, ok button) return true elsif src == cancel button (f) close (f, cancel button) return true end end return handle child event (super (f), src, evt) end //[cf] //[of]:actual release public func actual release (m: create link frame) actual release (super (m)) delete (new id (m)) delete (new name (m)) delete (new path (m)) end //[cf] //[cf] //[of]:private private equ ok button (f: create link frame) = components (f) [ok button] : button private equ cancel button (f: create link frame) = components (f) [cancel button] : button public equ id box (f: create link frame) = components (f) [create link id] : edit box public equ name box (f: create link frame) = components (f) [create link name] : edit box public equ path box (f: create link frame) = components (f) [create link path] : edit box //[cf] //[cf] //[of]:create folder //[of]:definition private enum create folder frame component create folder id = ok cancel max create folder name create folder cmax end //[c] public struct create folder frame : local dialog box components : [create folder cmax] object new name : string new id : string end //[c] public struct create folder frame class : local dialog box class end //[cf] //[of]:instance creation //[of]:new create folder frame public func new create folder frame (parent: box, style: box style, ro: bool) def f = allocate memory (sizeof local create folder frame): create folder frame initialize (f, parent, style, ro) return f end //[cf] //[cf] //[of]:accessing //[of]:name public func name (m: create folder frame) return new name (m) end //[cf] //[of]:id public func id (m: create folder frame) return new id (m) end //[cf] //[of]:set name public func set name (m: create folder frame, s: string) def t := temp string buffer escape string (t, s) set text (name box (m), as string (t)) release (t) end //[cf] //[of]:set id public func set id (m: create folder frame, s: string) set text (id box (m), s) end //[cf] //[cf] //[of]:restricted //[of]:rename folder frame class public func create folder frame class def c = the create folder frame class if ~ create folder initialized create folder initialized = true copy (c, dialog box class) release (c) = ^actual release (create folder frame) on child event (c) = ^handle child event (create folder frame, box, event) end return c end //[c] private def create folder initialized = false private def the create folder frame class: local create folder frame class //[cf] //[of]:initialize //[c] //[c]Initializes the frame //[c] public func initialize (f: create folder frame, parent: box, style: box style, ro: bool) initialize (f, parent, style, create folder frame class, cancel button, create folder res, components (f)) new name (f) = empty string new id (f) = empty string set read only (id box (f), ro) set read only (name box (f), ro) end //[c] //[c]Resources: //[c] def create folder res := dialog box resources ( create folder grid, str create folder title, 400, 100, ok button, cancel button) //[c] def create folder grid := grid box ( 5, default inner margin, const [] int (1, -1), const [] int (1, 0, -1), const grid cells ( grid cell (grid box ( 0, default inner margin, const [] int (0, 1, -1), const [] int (0, 0, 1, -1), const grid cells ( grid cell (label box (str folder name), 0, 0), grid cell (create folder name << edit box, 1, 0), grid cell (label box (str folder id), 0, 1), grid cell (create folder id << edit box, 1, 1), grid cell (blank box, 0, 2, 2, 1), nil) ), 0, 0), grid cell (ok cancel buttons, 0, 1), nil) ) //[cf] //[of]:handle child event public func handle child event (f: create folder frame, src: box, evt: event) if type (evt) == click event type if src == ok button (f) // copy string since the control is going to // be unbound on close(f) def t := temp string buffer unescape string (t, text (name box (f))) new name (f) = new string (t) release (t) new id (f) = new string (text (id box (f))) close (f, ok button) return true elsif src == cancel button (f) close (f, cancel button) return true end end return handle child event (super (f), src, evt) end //[cf] //[of]:actual release public func actual release (m: create folder frame) actual release (super (m)) delete (new name (m)) delete (new id (m)) end //[cf] //[c] //[cf] //[of]:private private equ ok button (f: create folder frame) = components (f) [ok button] : button private equ cancel button (f: create folder frame) = components (f) [cancel button] : button private equ name box (f: create folder frame) = components (f) [create folder name] : edit box private equ id box (f: create folder frame) = components (f) [create folder id] : edit box //[cf] //[cf] //[of]:cancel find //[of]:definition private enum cancel find frame component progress label = ok cancel max found label cancel find cmax end //[c] public struct cancel find frame : local dialog box components : [cancel find cmax] object end //[c] public struct cancel find frame class : local dialog box class end //[cf] //[of]:instance creation //[of]:new cancel find frame public func new cancel find frame (parent: box, style: box style, replace: bool) def f = allocate memory (sizeof local cancel find frame): cancel find frame initialize (f, parent, style, replace) return f end //[cf] //[cf] //[of]:accessing //[of]:set progression public func set progression (m: cancel find frame, text: string, count: dword) def s := temp string buffer printf (s, str find count, count) set text (label box (m), text) set text (found box (m), as string (s)) release (s) end //[cf] //[cf] //[of]:restricted //[of]:cancel find frame class public func cancel find frame class def c = the cancel find frame class if ~ cancel find initialized cancel find initialized = true copy (c, dialog box class) on child event (c) = ^handle child event (cancel find frame, box, event) end return c end //[c] private def cancel find initialized = false private def the cancel find frame class: local cancel find frame class //[cf] //[of]:initialize //[c]Initializes the frame //[c] public func initialize (f: cancel find frame, parent: box, style: box style, replace: bool) initialize (f, parent, style, cancel find frame class, cancel button, (replace -> replace res, find res), components (f)) set alignment (label box (f), align left) set can be truncated (label box (f), true) set alignment (found box (f), align left) set can be truncated (found box (f), true) end //[c] //[c]Resources: //[c] def find res := dialog box resources ( cancel find props grid, str search in progress, 600, 100, cancel button, cancel button) //[c] def replace res := dialog box resources ( cancel find props grid, str replace in progress, 600, 100, cancel button, cancel button) //[c] def cancel find props grid := grid box ( 5, default inner margin, const [] int (1, 0, 1, -1), const [] int (0, 0, 1, 0, -1), const grid cells ( grid cell (progress label << label box, 0, 0, 3, 1), grid cell (found label << label box, 0, 1, 3, 1), grid cell (blank box, 0, 2, 3, 1), grid cell (blank box, 0, 3), grid cell (cancel button << button (str cancel), 1, 3), grid cell (blank box, 2, 3), nil) ) //[cf] //[of]:handle child event public func handle child event (f: cancel find frame, src: box, evt: event) if type (evt) == click event type && src == cancel button (f) close (f, cancel button) return true end return handle child event (super (f), src, evt) end //[cf] //[c] //[cf] //[of]:private private equ cancel button (f: cancel find frame) = components (f) [cancel button] : button private equ label box (f: cancel find frame) = components (f) [progress label] : label box private equ found box (f: cancel find frame) = components (f) [found label] : label box //[cf] //[cf] //[of]:window selector //[of]:definition private enum window selector component window selector list box = ok cancel max window selector close button window selector cmax end //[c] public struct window selector : local dialog box components : [window selector cmax] object index : int close function: {object, int} void object: object end //[c] public struct window selector class : local dialog box class end //[cf] //[of]:instance creation //[of]:new window selector public func new window selector ( parent: box, style: box style, lines: vector of strings, index: int, close: {object, int} void) def f = allocate memory (sizeof local window selector): window selector initialize (f, parent, style, lines, index, close) return f end //[cf] //[cf] //[of]:restricted //[of]:window selector class public func window selector class def c = the window selector class if ~ window selector initialized window selector initialized = true copy (c, dialog box class) on child event (c) = ^handle child event (window selector, box, event) end return c end //[c] private def window selector initialized = false private def the window selector class: local window selector class //[cf] //[of]:initialize public func initialize ( f: window selector, parent: box, style: box style, lines: vector of strings, index: int, close: {object, int} void) initialize (f, parent, style, window selector class, cancel button, window selector res, components (f)) set list (list (f), lines, index) close function (f) = close object (f) = parent update close button enabling (f) end //[c] //[c]Resources: //[c] def window selector res := dialog box resources ( window selector grid, str window selector title, 600, 600, ok button, cancel button) //[c] def window selector grid := grid box ( 5, default inner margin, const [] int (1, -1), const [] int (1, 0, -1), const grid cells ( grid cell (window selector list box << list box, 0, 0), grid cell (window selector buttons, 0, 1), nil) ) //[c] def window selector buttons := grid box ( 0, 5, const [] int (0, 1, 0, 0, -1), const [] int (1, -1), const grid cells ( grid cell (window selector close button << button (str close window), 0, 0), grid cell (ok button << button (str ok), 2, 0), grid cell (cancel button << button (str cancel), 3, 0), nil) ) //[cf] //[of]:handle child event public func handle child event (f: window selector, src: box, evt: event) def t = type (evt) if t == click event type if src == close window button (f) close window (f) return true elsif src == ok button (f) activate window (f) return true elsif src == cancel button (f) cancel (f) return true end elsif t == mouse double click event type && src == list (f) activate window (f) elsif t == key down event type equ e = evt: key event def key = key (e) if key == VK DELETE || (status (e) == ALT && key == $C : int) click (close window button (f)) return true end end return handle child event (super (f), src, evt) end //[cf] //[c] //[cf] //[of]:private //[of]:activate window private func activate window (f: window selector) index (f) = index (list (f)) close (f, ok button) end //[cf] //[of]:cancel private func cancel (f: window selector) close (f, cancel button) end //[cf] //[of]:close window private func close window (f: window selector) def list = list (f) // close window close function (f) {object (f), index (list)} // remove an item from the listbox remove (list, index (list)) update close button enabling (f) end //[cf] //[of]:update close button enabling func update close button enabling (f: window selector) set enable (close window button (f), size of list (list (f)) > 1 ) end //[cf] //[c] //[of]:ok button private equ ok button (f: window selector) = components (f) [ok button] : button //[cf] //[of]:cancel button private equ cancel button (f: window selector) = components (f) [cancel button] : button //[cf] //[of]:close window button private equ close window button (f: window selector) = components (f) [window selector close button] : button //[cf] //[of]:list private equ list (f: window selector) = components (f) [window selector list box] : list box //[cf] //[cf] //[cf] //[of]:file manager //[of]:constants //[c]The value returned to open selection in new window: //[c] public equ open button = ok button //[cf] //[of]:definition private enum file manager component file manager list box = ok cancel max file manager fullname file manager relative indentation file manager read only file manager line feed type file manager unload button file manager cmax end //[c] public struct file manager : local dialog box private components : [file manager cmax] object files: local vector text file : text file file database : file database object : object close function : {object, text file} bool end //[c] public struct file manager class : local dialog box class end //[cf] //[of]:instance creation //[of]:new file manager public func new file manager ( parent: box, style: box style, db: file database, selection: text file, close function: {object, text file} bool) def f = allocate memory (sizeof local file manager): file manager initialize (f, parent, style, db, selection, close function) return f end //[cf] //[cf] //[of]:restricted //[of]:file manager class public func file manager class def c = the file manager class if ~ file manager initialized file manager initialized = true copy (c, dialog box class) release (c) = ^actual release (file manager) on child event (c) = ^handle child event (file manager, box, event) end return c end //[c] private def file manager initialized = false private def the file manager class: local file manager class //[cf] //[of]:initialize public func initialize ( f: file manager, parent: box, style: box style, db: file database, selection: text file, close function: {object, text file} bool) initialize (f, parent, style, file manager class, cancel button, file manager res, components (f)) object (f) = parent close function (f) = close function file database (f) = db set read only (fullname (f), true) set read only (read only box (f), true) set read only (relative indentation (f), true) def v := vector of strings (3) add (v, str end of line lf) add (v, str end of line cr) add (v, str end of line cr lf) set list (line feed type (f), v, 0) release (v) initialize list (f, db, selection) update selection (f) end //[c] //[c]Resources: //[c] def file manager res := dialog box resources ( file manager grid, str file manager title, 400, 500, open button, cancel button) //[c] def file manager grid := grid box ( 3, default inner margin, const [] int (0, 1, -1), const [] int (1, 0, 0, 0, 0, 0, -1), const grid cells ( grid cell (file manager list box << list box, 0, 0, 2, 1), grid cell (label box (str file path), 0, 1), grid cell (file manager fullname << edit box, 1, 1), grid cell (label box (str line feed type), 0, 2), grid cell (file manager line feed type << drop down list box, 1, 2), grid cell (file manager read only << check box (str read only), 1, 3), grid cell (file manager relative indentation << check box (str relative indentation), 1, 4), grid cell (file manager buttons, 0, 5, 2, 1), nil) ) //[c] def file manager buttons := grid box ( 0, 5, const [] int (0, 1, 0, 0, -1), const [] int (1, -1), const grid cells ( grid cell (file manager unload button << button (str unload file), 0, 0), grid cell (open button << button (str file manager open), 2, 0), grid cell (cancel button << button (str close caption), 3, 0), nil) ) //[cf] //[of]:handle child event public func handle child event (f: file manager, src: box, evt: event) def t = type (evt) if t == click event type if src == open button (f) open (f) return true elsif src == cancel button (f) cancel (f) return true elsif src == unload file button (f) unload (f) return true end elsif t == mouse double click event type if src == list (f) open (f) return true end elsif t == index changed event type if src == list (f) update selection (f) elsif src == line feed type (f) def file = selected text file (f) if not nil (file) def text style : int switch index (line feed type (f)) case 0; text style = text style unix case 1; text style = text style mac case 2; text style = text style dos end set text style (file, text style) end end elsif t == key down event type equ e = evt: key event def key = key (e) if (key == VK DELETE || (status (e) == ALT && key == $U : int) ) && can close (selected text file (f)) click (unload file button (f)) return true end end return handle child event (super (f), src, evt) end //[cf] //[of]:actual release public func actual release (f: file manager) release (files (f)) actual release (super (f)) end //[cf] //[cf] //[of]:private //[of]:open private func open (f: file manager) def text file = selected text file (f) if not nil (text file) text file (f) = text file close (f, open button) end end //[cf] //[of]:cancel private func cancel (f: file manager) close (f, cancel button) end //[cf] //[of]:unload private func unload (f: file manager) def text file = selected text file (f) if is nil (text file) return end if ~ close function (f) {object (f), text file} return end // remove the file from the listbox and the vector def list = list (f) def index = index (list) remove (files (f), index) remove (list, index) end //[cf] //[c] //[of]:initialize list (db, selection) func initialize list (f: file manager, db: file database, selection: text file) def n = number of files (db) def files = files (f) initialize (files, n) each file (db) ? text file insert (files, text file, 0, size (files)) end def l := array of strings (n) def t := temp string buffer def index = 0 def i = 0 each (files) ? e equ text file = e : text file remove all (t) append description (text file, t) add (l, as string (t)) if selection == text file index = i end ++i end release (t) set list (list (f), l, index) release (l) end //[c] //[c]Sub-Functions: //[of]:insert (vector, text file, a, b) func insert (l: vector, e: text file, a: dword, b: dword) : void if a == b add (l, e, a) else def n = b - a def m = a + n/2 if compare (e, l[m] : text file) < 0 insert (l, e, a, m) else insert (l, e, m+1, b) end end end //[cf] //[of]:compare (text file 1, text file 2) func compare (e: text file, f: text file) def t := temp string buffer def u := temp string buffer append description (e, t) append description (f, u) def result = compare (as string (t), as string (u)) release (u) release (t) return result end //[cf] //[cf] //[of]:update selection private func update selection (f: file manager) def text file = selected text file (f) // open button is available only is selection is valid set enable (open button (f), not nil (text file)) set enable (unload file button (f), can close (text file)) // fullname def t := temp string buffer if not nil (text file) t << \w << filename (text file) << \w end set text (fullname (f), as string (t)) release (t) // relative indentation and read only def enable = false def check = false def read only = false def new line = "\n" if not nil (text file) enable = can structure (text file) check = relative indentation (text file) read only = read only (text file) new line = new line (text file) end set enable (relative indentation (f), enable) set checked (relative indentation (f), check) set checked (read only box (f), read only) def index = 0 if new line [0] == \r index = ((new line [1] == \n) -> 2, 1) end set index (line feed type (f), index) end //[cf] //[of]:selected text file private func selected text file (f: file manager) def index = index (list (f)) if index == -1 return nil end return files (f) [index] : text file end //[cf] //[c] //[of]:open button private equ open button (f: file manager) = components (f) [open button] : button //[cf] //[of]:cancel button private equ cancel button (f: file manager) = components (f) [cancel button] : button //[cf] //[of]:unload file button private equ unload file button (f: file manager) = components (f) [file manager unload button] : button //[cf] //[of]:list private equ list (f: file manager) = components (f) [file manager list box] : list box //[cf] //[of]:fullname private equ fullname (f: file manager) = components (f) [file manager fullname] : edit box //[cf] //[of]:read only box private equ read only box (f: file manager) = components (f) [file manager read only] : check box //[cf] //[of]:line feed type private equ line feed type (f: file manager) = components (f) [file manager line feed type] : drop down list box //[cf] //[of]:relative indentation private equ relative indentation (f: file manager) = components (f) [file manager relative indentation] : check box //[cf] //[cf] //[cf] //[cf] //[c] //[of]:code browser frame //[of]:definitions //[of]:code browser frame box enum code browser frame components mdi dialogs status bar tools popup save command undo command redo command cut command copy command paste command paste raw text command copy reference command clear command select all command find next command find previous command mark all command unmark all command uppercase command lowercase command unfold command word wrap command one pane command hpane command vpane command browser 3 command browser 4 command browser 5 command vbrowser 3 command vbrowser 4 command vbrowser 5 command show tree command zoom command enter command leave command open in new tab command open target in new tab command next item command prev item command goto page 1 command goto page 2 command goto page 3 command goto page 4 command goto page 5 command goto page 6 command goto page 7 command goto page 8 command goto page 9 command insert text command insert comment command insert folder command insert link command open cmdline prefs command stop running tool command close window command clone window command cmax end //[c] equ mdi (m: frame) = components (m) [mdi] : multi view equ status bar (m: frame) = components (m) [status bar] : label box equ dialogs (m: frame) = components (m) [dialogs] : command box //[c] struct code browser frame box : local frame box // The application model application : application // Components generated from resources components : [cmax] object // File selector for open and save requests file selector : local file selector // Flags for aspects that need to be validated valid commands : bool valid status bar : bool valid title bar : bool valid tabs : bool valid properties : bool // Listen to events from any loaded text file file listener : local text file listener // The recipients for user tools user tool commands: [] local user tool command // Contextual commands // These commands are not created by a resource menu. // They are manually created and must be deleted when exiting. open in new tab command: command open target in new tab command: command edit properties command: command popup close command: command popup unload command: command // === Running Tool Information === // Current running process // nil if no running tool current running process: process // Current running tool // This object is a copy because settings could be reloaded during the // save-all or during the asynchronous process. current running tool: user tool // The current running tool has been cancelled current running tool cancelled : bool // Last line from pipe when capturing output of a running tool. // The line is buffered since it is not completed yet. buffered output line : local string buffer // Output window output window : code browser window // remember if we have already activated a link in the output window already activated : bool // user preference file user preference file : text file // === Contextual Menu Information === // These information is valid while executing a popup command // The folder for 'open in a new tab' context folder: text object context line: text line // Prevents re-entrance of check file update checking file updates: bool // Window to close: cannot be invoked from the popup menu since // it destroy the source of the event close me: code browser window // File to unload: cannot be invoked from the popup menu since // it destroy the source of the event unload me: text file // Open dialogs properties dialog: edit properties frame active text view: text view end //[cf] //[of]:code browser frame box class struct code browser frame box class : local frame box class end //[cf] //[cf] //[c] //[of]:instance creation //[of]:new code browser frame box public func new code browser frame box (application : application) def m = allocate memory ( sizeof local code browser frame box) : frame initialize (m, nil, application) return m end //[cf] //[cf] //[of]:initialize - release //[of]:code browser frame box class public func code browser frame box class def c = the code browser frame box class if ~ initialized initialized = true copy (c, frame box class) mem size (c) = sizeof local code browser frame box class release (c) = ^actual release (frame) on child event (c) = ^handle child event (frame, box, event) on close (c) = ^handle close (frame) on activation (c) = ^handle activation (frame, bool) on drop files (c) = ^handle drop files (frame, drop files event) on message (c) = ^handle message (frame, string) end return c end //[c] private def initialized = false private def the code browser frame box class: local code browser frame box class //[cf] //[of]:initialize public func initialize (m: frame, parent: box, application : application) initialize (super (m), parent, style (application)) class (m) = code browser frame box class set drag accept files (m, true) application (m) = application valid commands (m) = false valid status bar (m) = false valid title bar (m) = false valid tabs (m) = false valid properties (m) = false initialize file listener (m) current running process (m) = nil current running tool (m) = nil initialize (buffered output line (m)) output window (m) = nil close me (m) = nil unload me (m) = nil already activated (m) = false user preference file (m) = nil user tool commands (m) = nil checking file updates (m) = false properties dialog (m) = nil active text view (m) = nil add listener (file database (m), file listener (m)) set menu (m, new (main menu, m, components (m))) set icon (m, app icon id) new (main grid, m, components (m)) set default size (m, 700, 700) set alignment (status bar (m), align left) set tab position (mdi (m), tab position (settings (application))) initialize file selector (m) initialize commands (m) setup menu (m, settings (application)) open window (m, empty string) end //[c] //[c]Sub-functions: //[of]: initialize commands //[c] func initialize commands (m: frame) open in new tab command (m) = new command ( "popup-open-in-new-tab", str popup caption open in new tab, str popup desc open in new tab, 0: byte, 0, true, // enabled false, // not checked ^context open in new tab (frame), m) open target in new tab command (m) = new command ( "popup-open-target-in-new-tab", str popup caption open target in new tab, str popup desc open target in new tab, 0: byte, 0, true, // enabled false, // not checked ^context open target in new tab (frame), m) edit properties command (m) = new command ( "popup-edit-properties", str menu caption properties, str menu desc properties, 0: byte, 0, true, // enabled false, // not checked ^context edit properties (frame), m) popup close command (m) = new command ( "popup-close", str menu caption close window, str menu desc close window, 0: byte, 0, true, // enabled false, // not checked ^context close (frame), m) popup unload command (m) = new command ( "popup-unload", str menu caption unload, str menu desc unload, 0: byte, 0, true, // enabled false, // not checked ^context unload (frame), m) end //[cf] //[of]: initialize file listener //[c]Initializes the file listener //[c] //[c] Initializes the recipient (the frame box) and the function table. //[c] func initialize file listener (m: frame) def l = file listener (m) recipient (l) = m file changed (l) = ^handle file changed (frame, text file, bool) read only changed (l) = ^handle read only changed (frame, text file, bool) filename changed (l) = ^handle filename changed (frame, text file) end //[cf] //[of]: initialize file selector func initialize file selector (m: frame) def s = file selector (m) initialize (s) parent (s) = m filters (s) = const [] local pair of strings ( str all files, "*.*", //"C++ (*.cpp;*.h)", "*.cpp;*.h", nil, nil) filter index (s) = 1 end //[cf] //[c] //[c]Resources //[of]: main window def main grid := grid box ( const [] int (1, -1), const [] int (1, 0, 0, 0, 0, 0, -1), const grid cells ( grid cell (mdi << multi view, 0, 0), grid cell (blank box, 0, 1), grid cell (dialogs << command box, 0, 2), grid cell (separator box, 0, 3), grid cell (blank box, 0, 4), grid cell (status bar << label box, 0, 5), nil) ) //[cf] //[of]: main menu //[c]Useful alias... typedef frm = code browser frame box //[c] def main menu := top menu (const menu items ( //[of]: File popup menu (0, str menu caption file, const menu items ( command ( "file-new", str menu caption new, str menu desc new, CTRL, $N : int, ^new (frm)), command ( "file-open", str menu caption open, str menu desc open, CTRL, $O : int, ^open (frm)), save command << command ( "file-save", str menu caption save, str menu desc save, CTRL, $S : int, ^save (frm)), command ( "file-save-as", str menu caption save as, str menu desc save as, ^save as (frm)), command ( "file-save-all", str menu caption save all, str menu desc save all, CTRL|SHIFT, $S : int, ^save all (frm)), separator, command ( "file-files", str menu caption files, str menu desc files, ^open file manager (frm)), separator, command ( "exit", str menu caption exit, str menu desc exit, CTRL, $Q : int, ^close (frm)), nil)), //[cf] //[of]: Edit popup menu (0, str menu caption edit, const menu items ( undo command << command ( "edit-undo", str menu caption undo, str menu desc undo, CTRL, $Z : int, ^undo (frm)), redo command << command ( "edit-redo", str menu caption redo, str menu desc redo, CTRL, $Y : int, ^redo (frm)), separator, cut command << command ( "edit-cut", str menu caption cut, str menu desc cut, CTRL, $X : int, ^cut (frm)), copy command << command ( "edit-copy", str menu caption copy, str menu desc copy, CTRL, $C : int, ^copy (frm)), paste command << command ( "edit-paste", str menu caption paste, str menu desc paste, CTRL, $V : int, ^paste (frm)), clear command << command ( "edit-delete", str menu caption delete, str menu desc delete, ^clear (frm)), select all command << command ( "edit-select-all", str menu caption select all, str menu desc select all, CTRL, $A : int, ^select all (frm)), copy reference command << command ( "edit-copy-reference", str menu caption copy reference, str menu desc copy reference, ^copy reference (frm)), paste raw text command << command ( "edit-paste-raw-text", str menu caption paste raw text, str menu desc paste raw text, ^paste raw text (frm)), separator, command ( "toggle-bookmark", str menu caption toggle bookmark, str menu desc toggle bookmark, CTRL, VK F2, ^toggle bookmark (frm)), separator, uppercase command << command ( "edit-upper", str menu caption to upper, str menu desc to upper, CTRL|SHIFT, $U : int, ^to uppercase (frm)), lowercase command << command ( "edit-lower", str menu caption to lower, str menu desc to lower, CTRL, $U : int, ^to lowercase (frm)), separator, unfold command << command ( "edit-unfold", str menu caption unfold, str menu desc unfold, CTRL, $B : int, ^unfold (frm)), command ( "edit-properties", str menu caption properties, str menu desc properties, ALT, VK RETURN, ^edit properties (frm)), nil)), //[cf] //[of]: Search popup menu (0, str menu caption search, const menu items ( command ( "find", str menu caption find, str menu desc find, CTRL, $F : int, ^find (frm)), find next command << command ( "find-next", str menu caption find next, str menu desc find next, 0, VK F3, ^find next (frm)), find previous command << command ( "find-previous", str menu caption find previous, str menu desc find previous, SHIFT, VK F3, ^find previous (frm)), command ( "find-replace", str menu caption replace, str menu desc replace, CTRL, $R : int, ^replace (frm)), command ( "incremental-search", str menu caption incremental search, str menu desc incremental search, CTRL, $I : int, ^incremental search (frm)), separator, command ( "find-all", str menu caption find all, str menu desc find all, CTRL, $H : int, ^find all (frm)), command ( "find-replace-all", str menu caption replace all, str menu desc replace all, CTRL|SHIFT, $R : int, ^replace all (frm)), separator, command ( "find-in-files", str menu caption find in files, str menu desc find in files, 0, 0, ^find in files (frm)), command ( "find-replace-in-files", str menu caption replace in files, str menu desc replace in files, 0, 0, ^replace in files (frm)), separator, mark all command << command ( "mark-all", str menu caption mark all, str menu desc mark all, CTRL, $M : int, ^mark all (frm)), unmark all command << command ( "unmark-all", str menu caption unmark all, str menu desc unmark all, CTRL|SHIFT, $M : int, ^unmark all (frm)), nil)), //[cf] //[of]: View popup menu (0, str menu caption view, const menu items ( word wrap command << command ( "word-wrap", str menu caption word wrap, str menu desc word wrap, CTRL, $W : int, ^word wrap (frm)), separator, one pane command << command ( "view-one-pane", str menu caption one pane, str menu desc one pane, ALT, $1 : int, ^show one pane (frm)), hpane command << command ( "view-horizontal-panes", str menu caption hpanes, str menu desc hpanes, ALT, $2 : int, ^show hpanes (frm)), vpane command << command ( "view-vertical-panes", str menu caption vpanes, str menu desc vpanes, ALT, $3 : int, ^show vpanes (frm)), separator, browser 3 command << command ( "view-browser-3", str menu caption browser 3, str menu desc browser 3, ALT, $4 : int, ^show browser 3 (frm)), browser 4 command << command ( "view-browser-4", str menu caption browser 4, str menu desc browser 4, ALT, $5 : int, ^show browser 4 (frm)), browser 5 command << command ( "view-browser-5", str menu caption browser 5, str menu desc browser 5, ALT, $6 : int, ^show browser 5 (frm)), separator, vbrowser 3 command << command ( "view-vbrowser-3", str menu caption vbrowser 3, str menu desc vbrowser 3, ALT, $7 : int, ^show vbrowser 3 (frm)), vbrowser 4 command << command ( "view-vbrowser-4", str menu caption vbrowser 4, str menu desc vbrowser 4, ALT, $8 : int, ^show vbrowser 4 (frm)), vbrowser 5 command << command ( "view-vbrowser-5", str menu caption vbrowser 5, str menu desc vbrowser 5, ALT, $9 : int, ^show vbrowser 5 (frm)), separator, show tree command << command ( "view-tree", str menu caption tree view, str menu desc tree view, ALT, $0 : int, ^show tree (frm)), separator, command ( "page-view", str menu caption page view, str menu desc page view, ALT, $A : int, ^show page (frm)), zoom command << command ( "switch-zoom", str menu caption zoom, str menu desc zoom, ALT, VK END : int, ^zoom (frm)), nil)), //[cf] //[of]: Go popup menu (0, str menu caption go, const menu items ( leave command << command ( "go-back", str menu caption back, str menu desc back, ALT, VK LEFT, ^leave (frm)), enter command << command ( "go-enter", str menu caption enter, str menu desc enter, ALT, VK RIGHT, ^enter (frm)), popup menu (0, str menu caption page, const menu items ( goto page 1 command << command ("go-page-1", str menu caption page 1, str menu desc page n, CTRL, VK NUMPAD1, ^goto page 1 (frm)), goto page 2 command << command ("go-page-2", str menu caption page 2, str menu desc page n, CTRL, VK NUMPAD1, ^goto page 2 (frm)), goto page 3 command << command ("go-page-3", str menu caption page 3, str menu desc page n, CTRL, VK NUMPAD1, ^goto page 3 (frm)), goto page 4 command << command ("go-page-4", str menu caption page 4, str menu desc page n, CTRL, VK NUMPAD1, ^goto page 4 (frm)), goto page 5 command << command ("go-page-5", str menu caption page 5, str menu desc page n, CTRL, VK NUMPAD1, ^goto page 5 (frm)), goto page 6 command << command ("go-page-6", str menu caption page 6, str menu desc page n, CTRL, VK NUMPAD1, ^goto page 6 (frm)), goto page 7 command << command ("go-page-7", str menu caption page 7, str menu desc page n, CTRL, VK NUMPAD1, ^goto page 7 (frm)), goto page 8 command << command ("go-page-8", str menu caption page 8, str menu desc page n, CTRL, VK NUMPAD1, ^goto page 8 (frm)), goto page 9 command << command ("go-page-9", str menu caption page 9, str menu desc page n, CTRL, VK NUMPAD1, ^goto page 9 (frm)), nil)), separator, command ( "goto-line", str menu caption go to line, str menu desc go to line, CTRL, $G : int, ^goto line (frm)), command ( "goto-matching-bracket", str menu caption go to bracket, str menu desc go to bracket, ^goto matching bracket (frm)), command ( "select-matching-bracket", str menu caption select to bracket, str menu desc select to bracket, ^select matching bracket (frm)), separator, command ( "goto-next-bookmark", str menu caption next bookmark, str menu desc next bookmark, 0, VK F2, ^next bookmark (frm)), command ( "goto-previous-bookmark", str menu caption previous bookmark, str menu desc previous bookmark, SHIFT, VK F2, ^previous bookmark (frm)), separator, open in new tab command << command ( "go-open-in-new-tab", str menu caption open in new tab, str menu desc open in new tab, CTRL, $J : int, ^open in new tab (frm)), open target in new tab command << command ( "go-open-target-in-new-tab", str menu caption open target in new tab, str menu desc open target in new tab, CTRL, $T : int, ^open target in new tab (frm)), separator, next item command << command ( "go-next", str menu caption next item, str menu desc next item, CTRL|SHIFT, VK DOWN, ^next item (frm)), prev item command << command ( "go-previous", str menu caption previous item, str menu desc previous item, CTRL|SHIFT, VK UP, ^prev item (frm)), nil)), //[cf] //[of]: Insert popup menu (0, str menu caption insert, const menu items ( insert text command << command ( "insert-text", str menu caption insert text, str menu desc insert text, CTRL|SHIFT, $T : int, ^insert text line (frm)), insert comment command << command ( "insert-comment", str menu caption insert comment, str menu desc insert comment, CTRL|SHIFT, $C : int, ^insert comment line (frm)), insert folder command << command ( "insert-folder", str menu caption insert folder, str menu desc insert folder, CTRL|SHIFT, $F : int, ^insert new folder (frm)), insert link command << command ( "insert-link", str menu caption insert link, str menu desc insert link, CTRL|SHIFT, $L : int, ^insert new link (frm)), nil)), //[cf] //[of]: Tools tools popup << popup menu (0, str menu caption tools, const menu items ( command ( "tools-options", str menu caption options, str menu desc options, ^open options (frm)), command ("open-global-preferences", str menu caption global prefs, str menu desc global prefs, ^open global preferences (frm)), open cmdline prefs command << command ("open-cmdline-preferences", str menu caption cmdline prefs, str menu desc cmdline prefs, ^open cmdline preferences (frm)), separator, stop running tool command << command ( "tools-break", str menu caption stop running tool, str menu desc stop running tool, CTRL, VK CANCEL, false, false, ^stop running tool (frm)), nil)), //[cf] //[of]: Window popup menu (0, str menu caption window, const menu items ( close window command << command ( "window-close", str menu caption close window, str menu desc close window, 0, VK ESCAPE, ^close window (frm)), clone window command << command ( "window-clone", str menu caption clone window, str menu desc clone window, CTRL, $K : int, ^clone window (frm)), separator, command ( "window-next", str menu caption next window, str menu desc next window, ^next window (frm)), command ( "window-previous", str menu caption previous window, str menu desc previous window, ^previous window (frm)), separator, command ( "window-windows", str menu caption windows, str menu desc windows, ^select window (frm)), nil)), //[cf] //[of]: Help popup menu (0, str menu caption help, const menu items ( command ( "help-about", str menu caption about, str menu desc about, ^about (frm)), nil)), //[cf] nil)) //[cf] //[cf] //[of]:code browser message loop public func code browser message loop (m: frame) def cont = true while cont process close (m) process unload (m) poll (m) validate local commands (m) validate status bar (m) validate title (m) validate tabs (m) validate properties (m) cont = process message (m, true) end end //[c] //[c]Sub-functions: //[of]: process close //[c]Close window that requested it from the popup menu //[c] func process close (m: frame) if not nil (close me (m)) close window (m, close me (m)) close me (m) = nil end end //[cf] //[of]: process unload //[c]Unload file that requested it from the popup menu //[c] func process unload (m: frame) def text file = unload me (m) if not nil (text file) && can close (text file) close file (m, text file) unload me (m) = nil end end //[cf] //[of]: poll //[c]Checks status of running user tools //[c] //[of]: create text line (raw line, size) //[c] //[of]: starts with filename (raw line, size) //[c] equ starts with filename (s: string, size: size) = s[] == $/ || (size > 2 && s[1] == $: && (s[2] == $\ || s[2] == $/)) //[cf] //[c] public func create text line (raw line: string, size: size, directory: string) def line : text line def buffer = new string (raw line, size) def p = buffer def aln = 0:d def filename size = 0:d //if starts with filename (buffer, size) if size > 2 && p[1] == $: p += 2 end repeat def c = p++[] if is nul (c) --p break elsif c == $: && is digit (p[]) filename size = p - 1 - buffer def endptr : [1] string aln = number to dword (p, endptr) p = endptr[] break elsif c == $( && is digit (p[]) filename size = p - 1 - buffer def endptr : [1] string aln = number to dword (p, endptr) p = endptr[] if p[] == $) p = skip blanks (p+1) end break end end if p[] == $: ++p end p = skip blanks (p) //end if aln > 0 // extract filename def filename = new string (buffer, filename size) // convert to an uri, must use fullname def full name := temp string buffer if not empty (directory) resolve full name (directory, filename, full name) else full name (filename, full name) end def uri := convert filename to uri (as string (full name)) release (full name) delete (filename) def path := temp string buffer path << uri << "?aln=" << aln release (uri) def link = new link object (empty string, p, as string (path)) release (path) line = new link line (link) else line = new text line (buffer, size, lt comment) end delete (buffer) return line end //[cf] //[of]: poll std (m, not running) func poll std (m: frame, not running: bool) def proc = current running process (m) def tool = current running tool (m) def buffer = buffered output line (m) def has link = false // append appropriate message if terminated if not running if current running tool cancelled (m) buffer << str tool cancelled else appendf (buffer, str exit code, exit code (proc)) end end if not empty (buffer) // convert the buffer to a list of lines def list := list of lines def p = as string (buffer) def start = p repeat def c = p [] if is nul (c) break end def size = 0 repeat c = p++ [] if is nul (c) -- p break end // CR or CR+LF if c == \r // c must contain next char since if it is nul, // the line must not be flushed c = p [] if c == \n ++p end break end // LF if c == \n break end ++size end if not nul (c) def directory = directory (tool) def line = create text line (start, size, directory) add (list, line) if is link (line) has link = true end start = p end end remove (buffer, 0, start - base (buffer)) // check if the output window is opened and at end of the file def w = output window (m) def view = nil : text view def scroll = false if not nil (w) view = active view (w) if not nil (view) def cursor = cursor (view) def line = text line (cursor) scroll = is nil (next (line)) end end // Put lines in the output text file def text file = open (file database (m), output name) def lines = first (list) if not nil (lines) // terminates the list add (list, new empty default line) def folder = root folder (text file) def pos := bottom right position (folder) replace text (folder, pos, pos, lines) end // synchronize - prevents the output as being a modified document synchronize (text file) delete lines (list) if not nil (w) if has link && ~ already activated (m) && has preview (w) already activated (m) = true first item (w) enter (w) elsif scroll cursor bottom (view, false) end end end end //[cf] //[of]: poll lang (m, not running) func poll lang (m: frame, not running: bool) def proc = current running process (m) def tool = current running tool (m) def buffer = buffered output line (m) // check for termination if not running // Put lines in the output text file def text file = open (file database (m), output name) def text = new text object (empty string, empty string) def format: local text file format def language = language (tool) def prefix = line comment (language) def suffix = empty string if is empty (prefix) prefix = open comment (language) suffix = close comment (language) end directive prefix (format) = prefix directive suffix (format) = suffix relative indentation (format) = false set text file format (text file, format) load from buffer (text file, text, as string (buffer)) def folder = root folder (text file) def top = top left position (folder) def bottom := bottom right position (folder) replace text (folder, top, bottom, first line (text)) synchronize (text file) delete (text) remove all (buffer) end end //[cf] //[c] func poll (m: frame) def proc = current running process (m) if is nil (proc) return end // It is important to check only once the status of the process // because some chars may be written between the read stdout // and the last is running () check. def not running = ~ is running (proc) // read stdout def buffer = buffered output line (m) read stdout (proc, buffer) // convert to output def tool = current running tool (m) if is nil (language (tool)) poll std (m, not running) else poll lang (m, not running) end // check for termination if not running // auto close def w = output window (m) if not nil (w) && ~ already activated (m) && auto close (tool) && exit code (proc) == 0 close window (m, w) end set current running process (m, nil, nil) check file updates (m) end end //[cf] //[of]: validate status bar //[c]Updates the status bar if required //[c] func validate status bar (f: frame) if valid status bar (f) return end valid status bar (f) = true def t := temp string buffer def win = active window (f) if is nil (win) return end def view = active view (win) if not nil (view) def pos = cursor (view) def col = expanded column (pos, tabulation size (format (view))) printf (t, str line column, line number (pos) + 1, col + 1) end def text line = active line (win, nil) if not nil (text line) if is folder (text line) def folder = text object (text line) if not empty (t) t << " - " end t << id (folder) elsif is link (text line) def link = link object (text line) if not empty (t) t << " - " end if not empty (id (link)) t << id (link) t << ": " end t << path (link) end end // never empty t << space char set text (status bar (f), as string (t)) release (t) end //[cf] //[of]: validate local commands //[c]Updates local commands if required //[c] func validate local commands (f: frame) if valid commands (f) return end valid commands (f) = true def box = active (f) def can cut = false def can copy = false def can paste = false def can paste raw text = false def can clear = false def can select all = false def has target = false def has selection = false def has folder = false def can find = false def editable = false if not nil (box) can cut = can cut (box) can copy = can copy (box) can paste = can paste (box) can clear = can clear (box) can select all = can select all (box) def view = active text view (f) if not nil (view) def line = text line (cursor (view)) editable = ~ is read only (view) can paste raw text = can paste raw text (view) has selection = ~ is selection empty (view) has target = is headline (line) has folder = is folder (line) can find = true if ~ can paste can paste = can paste reference (f) end else def tree = as tree view (box) if not nil (tree) def selection = selection (tree) if not nil (selection) def line = text line (selection) has target = not nil (line) && is headline (line) has folder = not nil (line) && is folder (line) end end end end set enable (cmd (f, cut command), can cut) set enable (cmd (f, copy command), can copy) set enable (cmd (f, paste command), can paste) set enable (cmd (f, paste raw text command), can paste raw text) set enable (cmd (f, clear command), can clear) set enable (cmd (f, select all command), can select all) set enable (cmd (f, unfold command), has folder && editable) set enable (cmd (f, uppercase command), has selection && editable) set enable (cmd (f, lowercase command), has selection && editable) set enable (cmd (f, find next command), can find) set enable (cmd (f, find previous command), can find) set enable (cmd (f, mark all command), can find) set enable (cmd (f, unmark all command), can find) def text file = active text file (f) def can save = false def can undo = false def can redo = false def can insert text = false def can insert comment = false def can insert folder = false def can insert link = false def can copy reference = false def word wrap = false if not nil (text file) editable = ~ is read only (text file) can save = is modified (text file) if editable can undo = can undo (text file) can redo = can redo (text file) end def text view = active text view (f) if not nil (text view) can insert text = editable can insert comment = editable && can structure (text file) can insert folder = can insert comment can insert link = can insert comment can copy reference = true def folder = text (text view) if not nil (folder) word wrap = word wrap (find format (application (f), folder)) end end end set enable (cmd (f, save command), can save) set enable (cmd (f, undo command), can undo) set enable (cmd (f, redo command), can redo) set enable (cmd (f, insert text command), can insert text) set enable (cmd (f, insert comment command), can insert comment) set enable (cmd (f, insert folder command), can insert folder) set enable (cmd (f, insert link command), can insert link) set enable (cmd (f, copy reference command), can copy reference) set checked (cmd (f, word wrap command), word wrap) def win = active window (f) def can enter = false def can leave = false def has next item = false def has prev item = false def can zoom = false if not nil (win) can enter = can enter (win) can leave = can leave (win) has next item = has next item (win) has prev item = has prev item (win) can zoom = (layout (win) == pbm page) end set enable (cmd(f, zoom command), can zoom) set enable (cmd (f, enter command), can enter) set enable (cmd (f, leave command), can leave) set enable (cmd (f, open target in new tab command), has target) set enable (cmd (f, next item command), has next item) set enable (cmd (f, prev item command), has prev item) def n = 0 if not nil (win) n = last visible page number (win) end set enable (cmd (f, goto page 1 command), n >= 1) set enable (cmd (f, goto page 2 command), n >= 2) set enable (cmd (f, goto page 3 command), n >= 3) set enable (cmd (f, goto page 4 command), n >= 4) set enable (cmd (f, goto page 5 command), n >= 5) set enable (cmd (f, goto page 6 command), n >= 6) set enable (cmd (f, goto page 7 command), n >= 7) set enable (cmd (f, goto page 8 command), n >= 8) set enable (cmd (f, goto page 9 command), n >= 9) def cp = command preferences (application (f)) set enable (cmd (f, open cmdline prefs command), not nil (cp)) end //[cf] //[of]: validate title //[c]Updates the window's title if required //[c] func validate title (m: frame) if valid title bar (m) return end valid title bar (m) = true def t := temp string buffer def win = active window (m) if not nil (win) // append first (better in task bar) append description (win, t) t << " - " end t << app title set title (m, as string (t)) release (t) end //[cf] //[of]: validate tabs //[c]Updates the window's title if required //[c] func validate tabs (m: frame) if valid tabs (m) return end valid tabs (m) = true each window (m) ? win def t := temp string buffer append filename (win, t) set label (mdi (m), win, as string (t)) release (t) end end //[cf] //[cf] //[cf] //[of]:text file events //[of]:handle file changed public func handle file changed (m: frame, file: text file, modified: bool) if file == active text file (m) invalidate title (m) end invalidate tabs (m) end //[c] //[cf] //[of]:handle read only changed public func handle read only changed (m: frame, file: text file, ro: bool) invalidate local commands (m) invalidate properties (m) end //[c] //[cf] //[of]:handle filename changed public func handle filename changed (m: frame, text file: text file) if text file == active text file (m) invalidate title (m) invalidate tabs (m) end end //[cf] //[cf] //[of]:frame events //[of]:active view selection changed //[c]The selection of the active view has just changed //[c] func active view selection changed (m: frame) invalidate local commands (m) invalidate status bar (m) invalidate properties (m) end //[cf] //[of]:active line changed //[c]The active line has changed //[c] //[c] The active line is the line under the cursor in a text view or the line //[c] of the current selected folder or link in the tree view if the latter //[c] has the focus. //[c] func active line changed (f: frame) // update the active view def win = active window (f) active text view (f) = (not nil (win) -> active view (win), nil) invalidate properties (f) end //[cf] //[cf] //[of]:frame box interface //[of]:handle drop files //[c]The frame box has just receive one or more file from the desktop //[c] public func handle drop files (m: frame, e: drop files event) each file (e) ? filename open window (m, filename) end end //[cf] //[of]:handle child event //[c]Handles event emitted by children //[c] public func handle child event (f: frame, src: box, evt: event) def t = type (evt) if t == destroy event type // if no more window opened, re-opened an untitled document if running (f) && // do not attempt to reopen window if exiting number of views (mdi (f)) == 0 open window (f, empty string) end if src == output window (f) output window (f) = nil elsif src == properties dialog (f) properties dialog (f) = nil end elsif t == value changed event type if active (f) == src // some local commands depend on the // content invalidate local commands (f) invalidate status bar (f) end elsif t == selection changed event type if src == active text view (f) active view selection changed (f) elsif src == active (f) // can be an edit: must update cut/copy/paste... commands invalidate local commands (f) elsif src == mdi (f) active line changed (f) end elsif t == focus event type active line changed (f) invalidate local commands (f) invalidate status bar (f) invalidate title (f) // The focus can change inside a tab, requiring to update // the label of tabs. A specific notif should be emitted instead // (title changed event). invalidate tabs (f) elsif t == folder destroyed event type close window (f, src: code browser window) elsif t == folder changed event type if active window (f) == src invalidate title (f) active view selection changed (f) end invalidate tabs (f) elsif t == key down event type equ e = evt: key event // Extra shortcuts: // Some commands are not in the menu or have already // a shortcut. def key = key (e) if key==VK DELETE & status (e) == SHIFT cut (f) return true elsif key==VK INSERT & status (e) == SHIFT paste (f) return true elsif key==VK INSERT & status (e) == CTRL copy (f) return true elsif key==VK F3 & status (e) == CTRL find next selection (f) return true elsif key==VK F3 & status (e) == (CTRL|SHIFT) find previous selection (f) return true elsif key==VK BACK && status (e) == ALT undo (f) return true elsif key==VK OEM 6 && status (e) == CTRL goto matching bracket (f) return true elsif key==VK OEM 6 && status (e) == (CTRL|SHIFT) select matching bracket (f) return true end elsif t == popup event type equ e = evt : popup event def view = as text view (src) if not nil (view) def source folder = text (view) context folder (f) = source folder def pos := text position under point (view, position (e)) def line = text line (pos) def has target = is link (line) | is folder (line) context line (f) = line def menu = new popup menu (0, empty string) append menu (menu, cmd (f, leave command)) append menu (menu, open in new tab command (f)) if has target set highlight line (view, line) append menu (menu, open target in new tab command (f)) end append separator (menu) append menu (menu, cmd (f, cut command)) append menu (menu, cmd (f, copy command)) append menu (menu, cmd (f, paste command)) append menu (menu, cmd (f, clear command)) append menu (menu, cmd (f, select all command)) append separator (menu) append menu (menu, popup unload command (f)) append menu (menu, popup close command (f)) if has target append separator (menu) append menu (menu, edit properties command (f)) end show popup (menu, position (e), view) delete (menu) set highlight line (view, nil) return true end def tree view = as tree view (src) if not nil (tree view) def selection = selection (tree view) if is nil (selection) return true end def text object = text object (selection) def text line = text line (selection) if is nil (text line) return true end context folder (f) = text object context line (f) = text line def menu = new popup menu (0, empty string) append menu (menu, open target in new tab command (f)) append separator (menu) append menu (menu, popup unload command (f)) append menu (menu, popup close command (f)) append separator (menu) append menu (menu, edit properties command (f)) show popup (menu, position (e), tree view) delete (menu) return true end end return handle child event (super (f), src, evt) end //[cf] //[of]:handle close //[c]Requests to close the frame box //[c] public func handle close (m: frame) def do not close = false each file (file database (m)) ? text file if is modified (text file) def code = ask save (m, text file) if code == id cancel // return without closing return true elsif code == id yes if not ok (save (m, text file, false)) do not close = true end end end end return do not close end //[cf] //[of]:handle activation //[c]The frame is being activated or deactivated //[c] //[c]We must check on activation if files have been updated //[c] public func handle activation (m: frame, active: bool) // do nothing on deactivation if ~ active return end check file updates (m) end //[cf] //[of]:handle message public func handle message (m: frame, message: string) def filename := temp string buffer def p = message while not nul (p[]) remove all (filename) p = unserialize (filename, p) open window (m, as string (filename), true) end release (filename) end //[cf] //[of]:actual release //[c]Releases all resources allocated by the frame box //[c] public func actual release (m: frame) // Release commands delete (popup close command (m)) delete (popup unload command (m)) delete (open in new tab command (m)) delete (open target in new tab command (m)) delete (edit properties command (m)) set user tool array (m, 0) delete (current running process (m)) delete (current running tool (m)) release (buffered output line (m)) release (file selector (m)) actual release (super (m)) end //[cf] //[cf] //[of]:commands (menu) //[c]All menu commands //[c] //[of]:File //[of]:new func new (m: frame) def path := temp string buffer def active = active text file (m) if not nil (active) def old = filename (active text file (m)) append file path (path, old) end def s = file selector (m) // new is like a save: // - allows non existent // - warn on overwrite save (s) = true title (s) = str new title initial name (s) = empty string initial path (s) = as string (path) if open (s) def fn := temp string buffer get filename (s, fn) def text file = create (file database (m), as string (fn)) if not nil (text file) open window (m, text file) else show file error (m, last error (file database (m))) end release (fn) end release (path) end //[cf] //[of]:open func open (m: frame) def path := temp string buffer def active = active text file (m) if not nil (active) def old = filename (active text file (m)) append file path (path, old) end def s = file selector (m) save (s) = false title (s) = str open title initial name (s) = empty string initial path (s) = as string (path) if open (s) def fn := temp string buffer get filename (s, fn) open window (m, as string (fn)) release (fn) end release (path) end //[cf] //[of]:save all func save all (m: frame) try save all (m) end //[cf] //[of]:save func save (m: frame) save (m, false) end //[cf] //[of]:save as func save as (m: frame) save (m, true) end //[cf] //[of]:open file manager func open file manager (m: frame) def db = file database (m) def selection = active text file (m) def frame = new file manager (m, style (m), db, selection, ^close file (frame, text file)) def res = show modal (frame) if res == open button open window (m, text file (frame)) end delete (frame) end //[cf] //[of]:close //[c]Exit application //[c] func close (m: frame) close (super (m)) end //[cf] //[cf] //[of]:Edit //[c]Active window: //[of]:undo func undo (m: frame) def w = active window (m) if is nil (w) return end undo (w) end //[cf] //[of]:redo func redo (m: frame) def w = active window (m) if is nil (w) return end redo (w) end //[cf] //[c] //[c]Active box: //[of]:cut func cut (m: frame) if can cut (active (m)) cut (active (m)) end end //[cf] //[of]:copy func copy (m: frame) if can copy (active (m)) copy (active (m)) end end //[cf] //[of]:paste func paste (m: frame) // is there a reference to paste if paste reference (m) return true end if can paste (active (m)) return paste (active (m)) else return false end end //[cf] //[of]:clear func clear (m: frame) clear (active (m)) end //[cf] //[of]:select all func select all (m: frame) select all (active (m)) end //[cf] //[c] //[c]Active text view: //[of]:copy reference func copy reference (m: frame) def view = active text view (m) if is nil (view) return end def text object = text (view) def text file = find text file (file database (m), text object) if is nil (text file) return end def t := temp string buffer def valid = append id (t, text object) if valid def filename = filename (text file) def uri := convert filename to uri (filename) set fragment (uri, as string (t)) remove all (t) t << uri set clipboard content ? def cf = cf text reference (application (m)) set clipboard data (cf, base (t) : [] byte, size (t)) end release (uri) else message box (m, str cannot copy reference, nil, mb ok) end release (t) end //[c] func append id (s: string buffer, t: text object) : bool def line = parent line (t) if is nil (line) return true end append id (s, parent folder (t)) def id = id (t) if is empty (id) return false end if not empty (s) s << $/ end s << id return true end //[cf] //[of]:paste raw text func paste raw text (m: frame) def view = active text view (m) if not nil (view) paste raw text (view) end end //[cf] //[c] //[of]:insert text line func insert text line (m: frame) def view = active text view (m) if not nil (view) insert text line (view) end end //[cf] //[of]:insert comment line func insert comment line (m: frame) def view = active text view (m) if not nil (view) && can structure (m) insert comment line (view) end end //[cf] //[of]:insert new folder func insert new folder (m: frame) def view = active text view (m) if is nil (view) || ~ can structure (m) return end // Get a default title for the folder // If there is a selection and the first line is not empty, // the default title is the content of the first line. def name = str default section name def empty selection = is selection empty (view) if ~ empty selection def start = min (block (view), cursor (view)) def cursor line = text line (start) if size (cursor line) > 0 name = buf (cursor line) end end def frame = new create folder frame (m, style (m), false) set name (frame, name) def res = show modal (frame) if res == ok button def lines: local list of lines if is selection empty (view) initialize (lines) def settings = settings (application (m)) if comment line (settings) add (lines, new empty comment line) end add (lines, new empty text line) else initialize (lines, cursor (view), block (view)) delete selection (view) // can't be nil def last line = last (lines) if is default (last line) remove last (lines) delete (last line) end // Indent the unfolded content if the text file has relative indentation def text file = find text file (file database (m), text (view)) if not nil (text file) && relative indentation (text file) unindent lines (lines, name (frame)) end end add (lines, new empty comment line) insert folder (view, id (frame), name (frame), lines) // Enter into the folder to allow editing its content // It should be ok: the current selection is the newly created folder if empty selection enter (m) end end delete (frame) end //[c] //[c]Sub-functions: //[of]: unindent lines (lines, name) func unindent lines (lines: list of lines, name: string) def t := temp string buffer def limit = skip blanks (name) def indent size = limit - name each (lines) ? text line remove all (t) if is headline (text line) def hyper text = hyper text object (text line) def p = skip blanks (title (hyper text), name, limit) set hyper text properties (text line, id (hyper text), p) else def text = buf (text line) def p = skip blanks (text, name, limit) replace line (lines, text line, new text line (p, size (text line) - (p - text), type (text line))) end end release (t) end //[c] //[c]Sub-functions: //[of]: skip blanks (s, start, limit) func skip blanks (s: string, start: string, limit: string) def p = s def q = start while q:mem <> limit:mem && p[]==q[] p += 1 q += 1 end return p end //[cf] //[cf] //[cf] //[of]:insert new link func insert new link (m: frame) def view = active text view (m) if is nil (view) || ~ can structure (m) return end def frame = new create link frame (m, style (m), false) set name (frame, str default link name) set path (frame, str default link path) def res = show modal (frame) if res == ok button insert link (view, id (frame), name (frame), path (frame)) end delete (frame) end //[cf] //[c] //[of]:toggle bookmark func toggle bookmark (m: frame) def win = active window (m) if is nil (win) return end def view = active view (win) def folder = text (view) def start : local text position def limit : local text position set (start, cursor (view)) set (limit, block (view)) // Empty selection // - if there is another bookmark under the cursor, delete it // - otherwise create it if start == limit // Remove all bookmarks under the selection def removed = remove markers (folder, mt bookmark, start, limit) if removed return end // Select all the line column (start) = 0 def line = text line (start) def next = next (line) if not nil (next) text line (limit) = next column (limit) = 0 ++ line number (limit) else def col = size (text line (limit)) : int // can't bookmark the last line if empty if col == 0 return end column (limit) = col end else // reset the selection (otherwise the marker will be hidden // by the selection def cursor = cursor (view) cursor to (view, line number (cursor), column (cursor), false) end // Remove all bookmarks under the selection remove markers (folder, mt bookmark, start, limit) add marker (folder, mt bookmark, start, limit) end //[cf] //[c] //[of]:to uppercase //[c]Makes selection uppercase //[c] func to uppercase (m: frame) def view = active text view (m) if not nil (view) uppercase selection (view) end end //[cf] //[of]:to lowercase //[c]Makes selection lowercase //[c] func to lowercase (m: frame) def view = active text view (m) if not nil (view) lowercase selection (view) end end //[cf] //[of]:unfold //[c]Unfold the folder under the cursor //[c] //[c]Remark: //[c] the implementation is not efficient at all. The content is copied twice //[c] plus the copy for the undo buffer. //[c] func unfold (m: frame) def view = active text view (m) if is nil (view) return end def cursor = cursor (view) def text line = text line (cursor) if ~ is folder (text line) return end // Copy the content of the folder into a text object def content = text object (text line) def start := top left position (content) def limit := bottom right position (content) def lines := list of lines (start, limit) // Indent the unfolded content if the text file has relative indentation def text file = find text file (file database (m), content) if not nil (text file) && relative indentation (text file) indent lines (content, lines) end // Replace the current line def start line : local text position def limit line : local text position def line number = line number (cursor) initialize (start line, 0, line number, text line) initialize (limit line, 0, line number + 1, next (text line)) replace text (text (view), start line, limit line, first (lines)) //Delete the copy delete lines (lines) end //[c] //[c]Sub-functions: //[of]: indent lines (text object, lines) func indent lines (text object: text object, lines: list of lines) def t := temp string buffer def start = title (text object) def limit = skip blanks (start) def indent size = limit - start append (t, start, indent size) each (lines) ? text line if ~ is last line (text line) set size (t, indent size) if is headline (text line) def hyper text = hyper text object (text line) t << title (hyper text) set hyper text properties (text line, id (hyper text), as string (t)) else t << buf (text line) replace line (lines, text line, new text line (t, type (text line))) end end end release (t) end //[cf] //[cf] //[of]:edit properties //[c]Edits properties for the current selected object //[c] //[c]The object can be //[c]- a folder line //[c]- a link line //[c] //[c]The method has no effect on other types of line. //[c] func edit properties (m: frame) open properties (m) invalidate properties (m) end //[cf] //[cf] //[of]:Search //[of]:find next func find next (m: frame) find (m, find next, false) end //[cf] //[of]:find previous func find previous (m: frame) find (m, find previous, false) end //[cf] //[of]:find next selection func find next selection (m: frame) find (m, find next, true) end //[cf] //[of]:find previous selection func find previous selection (m: frame) find (m, find previous, true) end //[cf] //[of]:incremental search func incremental search (m: frame) open find dialog (m, find incremental, false) end //[cf] //[c] //[of]:find func find (m: frame) open find dialog (m, find iterative, false) end //[cf] //[of]:replace func replace (m: frame) open find dialog (m, find iterative, true) end //[cf] //[of]:find all func find all (m: frame) open find dialog (m, find all, false) end //[cf] //[of]:replace all func replace all (m: frame) open find dialog (m, find all, true) end //[cf] //[of]:find in files func find in files (m: frame) open find dialog (m, find in files, false) end //[cf] //[of]:replace in files func replace in files (m: frame) open find dialog (m, find in files, true) end //[cf] //[c] //[of]:mark all func mark all (m: frame) def data = find data (m) match whole word (data) = false regular expression (data) = false get selection (m, data) do mark all (m) end //[cf] //[of]:unmark all func unmark all (m: frame) def win = active window (m) if is nil (win) return end def view = active view (win) def folder = active folder (win) folder = root folder (folder) remove all markers (folder) end //[c] func remove all markers (folder: text object): void remove all markers (folder, mt match) each line (folder) ? line if is folder (line) remove all markers (text object (line)) end end end //[cf] //[cf] //[of]:View //[of]:word wrap //[c]Switch word wrapping //[c] func word wrap (m: frame) def view = active text view (m) if is nil (view) return end def app = application (m) def text object = text (view) def format = find format (app, text object) word wrap (format) = ~ word wrap (format) invalidate local commands (m) // notify windows // Any text view using this format must be notified def settings = settings (app) each window (m) ? win settings changed (win, settings, settings) end end //[cf] //[of]:zoom //[c]Switch zoom //[c] func zoom (m: frame) def win = active window (m) if is nil (win) return end zoom (win) end //[cf] //[c] //[of]:show one pane //[c]Shows one pane //[c] func show one pane (m: frame) change layout (m, pbm single) end //[cf] //[of]:show hpanes //[c]Shows one pane //[c] func show hpanes (m: frame) change layout (m, pbm horizontal) end //[cf] //[of]:show vpanes //[c]Shows one pane //[c] func show vpanes (m: frame) change layout (m, pbm vertical) end //[cf] //[of]:show browser 3 //[c]Shows one pane //[c] func show browser 3 (m: frame) change layout (m, pbm browser 3) end //[cf] //[of]:show browser 4 //[c]Shows one pane //[c] func show browser 4 (m: frame) change layout (m, pbm browser 4) end //[cf] //[of]:show browser 5 //[c]Shows one pane //[c] func show browser 5 (m: frame) change layout (m, pbm browser 5) end //[cf] //[of]:show vbrowser 3 //[c]Shows one pane //[c] func show vbrowser 3 (m: frame) change layout (m, pbm vbrowser 3) end //[cf] //[of]:show vbrowser 4 //[c]Shows one pane //[c] func show vbrowser 4 (m: frame) change layout (m, pbm vbrowser 4) end //[cf] //[of]:show vbrowser 5 //[c]Shows one pane //[c] func show vbrowser 5 (m: frame) change layout (m, pbm vbrowser 5) end //[cf] //[of]:show tree //[c]Shows the tree view //[c] func show tree (m: frame) change layout (m, pbm tree) def win = active window (m) if not nil (win) activate tree (win) end end //[cf] //[of]:show page //[c]Shows the tree view //[c] func show page (m: frame) change layout (m, pbm page) end //[cf] //[cf] //[of]:Go //[of]:enter //[c]Enter into the current line //[c] func enter (m: frame) def win = active window (m) if is nil (win) return end enter (win) end //[cf] //[of]:leave //[c]Returns to the previous folder //[c] func leave (m: frame) def win = active window (m) if is nil (win) return end leave (win) end //[cf] //[of]:open in new tab func open in new tab (m: frame) def window = active window (m) if is nil (window) return end def folder = active folder (window) if is nil (folder) return end open window (m, folder) end //[cf] //[of]:open target in new tab func open target in new tab (m: frame) def box = active (m) if is nil (box) return end def folder = nil: text object def line = nil: text line def view = as text view (box) def tree = as tree view (box) if not nil (view) folder = text (view) line = text line (cursor (view)) elsif not nil (tree) def selection = selection (tree) if not nil (selection) folder = text object (selection) line = text line (selection) end end if not nil (line) && is headline (line) open target (m, folder, line) end end //[cf] //[of]:next item func next item (m: frame) def win = active window (m) if is nil (win) return end next item (win) end //[cf] //[of]:prev item func prev item (m: frame) def win = active window (m) if is nil (win) return end prev item (win) end //[cf] //[c] //[of]:goto page 1 func goto page 1 (m: frame) goto page (m, 1) end //[cf] //[of]:goto page 2 func goto page 2 (m: frame) goto page (m, 2) end //[cf] //[of]:goto page 3 func goto page 3 (m: frame) goto page (m, 3) end //[cf] //[of]:goto page 4 func goto page 4 (m: frame) goto page (m, 4) end //[cf] //[of]:goto page 5 func goto page 5 (m: frame) goto page (m, 5) end //[cf] //[of]:goto page 6 func goto page 6 (m: frame) goto page (m, 6) end //[cf] //[of]:goto page 7 func goto page 7 (m: frame) goto page (m, 7) end //[cf] //[of]:goto page 8 func goto page 8 (m: frame) goto page (m, 8) end //[cf] //[of]:goto page 9 func goto page 9 (m: frame) goto page (m, 9) end //[cf] //[of]:goto page func goto page (m: frame, n: int) def win = active window (m) if is nil (win) return end goto page (win, n) end //[cf] //[c] //[of]:goto line func goto line (m: frame) def frame = new goto line frame (dialogs (m), m) show child (dialogs (m), ok button (frame), cancel button (frame)) end //[cf] //[of]:goto matching bracket func goto matching bracket (m: frame) find bracket (m, false) end //[cf] //[of]:select matching bracket func select matching bracket (m: frame) find bracket (m, true) end //[cf] //[c] //[of]:next bookmark func next bookmark (m: frame) goto bookmark (m, false) end //[cf] //[of]:previous bookmark func previous bookmark (m: frame) goto bookmark (m, true) end //[cf] //[cf] //[of]:Tools //[of]:open options func open options (m: frame) /* * Once opened, the user preference file will be always the same object, * even if the file is renamed. That's why it is strongly recommended * to avoid renaming this file. * * Anyway it is not a bug, and it will continue to work after a save as; * the 'reload settings' just reload an identical file. * * Note: File/Open... opens the config file as a regular file, i.e. settings * won't be reloaded on save. */ def pref file = user preference file (m) if is nil (pref file) def fn := user resource filename (preferences path, preferences filename) def filename = as string (fn) if file exists (filename) pref file = open (file database (m), filename) release (fn) if is nil (pref file) show file error (m, last error (file database (m))) return end else def fn default := program resource filename (preferences default path, preferences filename) pref file = open (file database (m), as string (fn default)) release (fn default) if is nil (pref file) show file error (m, last error (file database (m))) release (fn) return end // Rename to user file set filename (pref file, filename) set read only (pref file, false) release (fn) end user preference file (m) = pref file end open window (m, pref file) end //[cf] //[of]:open global preferences func open global preferences (m: frame) def filename := program resource filename (preferences path, preferences filename) open window (m, as string (filename), true) release (filename) end //[cf] //[of]:open cmdline preferences func open cmdline preferences (m: frame) def filename = filename (command preferences (application (m))) if not empty (filename) open window (m, filename, true) end end //[cf] //[c] //[of]:stop running tool func stop running tool (m: frame) def proc = current running process (m) if not nil (proc) stop (proc) current running tool cancelled (m) = true end end //[cf] //[of]:user tool //[c]Executes a user defined tool //[c] //[c] Sub-functions //[of]: append arguments (string buffer, m, arguments) //[c]Appends arguments //[c] //[c] The arguments string is expanded and added to the string buffer //[c] //[c] def argument variables = const [] local word dictionary pair ( "FilePath", 0, "FileDir", 1, "FileName", 2, //"FileExt", 3, "FileNameExt", 4, "CurText", 5, "CurLine", 6, "CurCol", 7, nil:string, 0 ) //[c] //[c] func append arguments (s: string buffer, m: frame, args: string) def dict : local word dictionary initialize (dict, true, argument variables) def p = args repeat def c = p++ [] if is nul (c) break elsif c == $$ && p [] == $( ++p def var name = p while is alpha (p[]) ++p end def var name size = p - var name if p[] == $) ++p end def text file = active text file (m) switch state (dict, var name, var name size) case 0 if not nil (text file) s << filename (text file) end case 1 if not nil (text file) append file path (s, filename (text file)) end case 2 if not nil (text file) append name (s, filename (text file)) end case 4 if not nil (text file) append base name (s, filename (text file)) end case 5 def view = active text view (m) if not nil (view) append selection (view, s) end case 6 def view = active text view (m) if not nil (view) def cursor = cursor (view) def folder = text (view) def text line = text line (cursor) def ln = absolute line number (folder, text line) s << (ln + 1) end case 7 def view = active text view (m) if not nil (view) def cursor = cursor (view) s << (column (cursor) + 1) end end else s << c end end release (dict) end //[cf] //[c] func user tool (u: user tool command) def m = frame (u) // Get the tool to launch def tool = copy (tool (u)) // Build the command line def a := temp string buffer def d := temp string buffer append arguments (a, m, arguments (tool)) append arguments (d, m, directory (tool)) // Edit arguments (if option is set) if edit arguments (tool) def frame = new edit arguments frame (dialogs (m), m, tool, caption (tool), as string (a), as string (d)) show child (dialogs (m), ok button (frame), cancel button (frame)) else run tool (m, tool, as string (a), as string (d)) end release (a) release (d) end //[c] func run tool (m: frame, tool: user tool, arguments: string, directory: string) // Check first if another tool is still running // Currently, it is not possible to track several running processes if not nil (current running process (m)) message box (m, str tool already running, nil, mb ok) delete (tool) return end // Save all if required if save all (tool) def success = try save all (m) // do not run tool if the save all command has failed if ~ success delete (tool) return end end def t := temp string buffer t << $" << command (tool) << $" << \w << arguments // Create the process def process = create process ( as string (t), directory, show window (tool), true) release (t) if ~ ok (process) message box (m, str cannot run tool, nil, mb ok) delete (process) delete (tool) return end set current running process (m, process, tool) current running tool cancelled (m) = false // get the text file to store output def text file = open (file database (m), output name) // Reset its content, change title def text object = new text object (empty string, caption (tool)) add (text object, new empty comment line) set text (text file, text object) // open the window to show search result def w = open window (m, text file) set layout (w, mode (tool)) output window (m) = w already activated (m) = false end //[cf] //[c] //[cf] //[of]:Window //[of]:close window //[c]Closes the active window //[c] func close window (m: frame) if ~ is empty (dialogs (m)) hide child (dialogs (m)) return end def w = active window (m) if not nil (w) close window (m, w) end end //[cf] //[of]:clone window //[c]Clones the active window //[c] func clone window (m: frame) def src = active window (m) if is nil (src) return end def win = new code browser window (mdi (m), application (m), src) add window (m, win) set current window (m, win) end //[cf] //[c] //[of]:next window //[c]Switches to the next window //[c] func next window (m: frame) next (mdi (m)) end //[cf] //[of]:previous window //[c]Switches to the previous window //[c] func previous window (m: frame) previous (mdi (m)) end //[cf] //[of]:select window //[c]Opens the window selector //[c] func select window (m: frame) def n = number of views (mdi (m)) // do not open selector if zero opened window // (it should never happen) if n==0 return end def l := array of strings (n) def t := temp string buffer def index = 0 def i = 0 def active window = active window (m) each view (mdi (m)) ? view remove all (t) append description (view : code browser window, t) add (l, as string (t)) if active window == view index = i end ++i end release (t) def frame = new window selector (m, style (m), l, index, ^close from index(frame, int)) release (l) def res = show modal (frame) if res == ok button set index (mdi (m), index (frame), true) end delete (frame) end //[c] func close from index (m: frame, i: int) def c = 0 def w = nil : code browser window each view (mdi (m)) ? view if c == i w = view : code browser window end ++ c end if not nil (w) close window (m, w) end end //[cf] //[cf] //[of]:Help //[of]:about //[c]Display a simple about box //[c] func about (m: frame) def msg := temp string buffer msg << app title msg << str copyright message box (m, as string (msg), app title, mb ok) release (msg) end //[cf] //[cf] //[cf] //[of]:commands (popup) //[of]:context open in new tab func context open in new tab (m: frame) open window (m, context folder (m)) end //[cf] //[of]:context open target in new tab func context open target in new tab (m: frame) open target (m, context folder (m), context line (m)) end //[cf] //[of]:context edit properties func context edit properties (m: frame) open properties (m) // forces the selection set line (properties dialog (m), context folder (m), context line (m)) valid properties (m) = true end //[cf] //[of]:context close func context close (m: frame) // the window is not closed immediately, it will be closed // when re-entering the main loop. close me (m) = active window (m) end //[cf] //[of]:context unload func context unload (m: frame) // the file is not unloaded immediately, it will be unloaded // when re-entering the main loop. unload me (m) = active text file (m) end //[cf] //[cf] //[of]:properties //[of]:open properties //[c]Open the 'edit properties' dialog //[c] func open properties (m: frame) if not nil (properties dialog (m)) set focus (properties dialog (m)) return end def frame = new edit properties frame (dialogs (m), m) show child (dialogs (m), apply button (frame), close button (frame)) properties dialog (m) = frame end //[cf] //[of]:invalidate properties func invalidate properties (m: frame) valid properties (m) = false end //[cf] //[of]:validate properties //[c]Updates the window's title if required //[c] func validate properties (m: frame) if valid properties (m) return end valid properties (m) = true def frame = properties dialog (m) if is nil (frame) return end def win = active window (m) if is nil (win) return end def folder : [1] text object def line = active line (win, folder) set line (frame, folder[], line) end //[cf] //[cf] //[of]:find //[of]:find //[c]Finds with the given direction //[c] //[c] if 'use selection' is set, the search is performed using the selection //[c] or the word under the cursor. //[c] func find (m: frame, direction: find direction, use selection: bool) def win = active window (m) if is nil (win) return end def data = find data (m) if use selection match whole word (data) = false regular expression (data) = false get selection (m, data) end direction (data) = direction def found = find (m, false) if ~ found message box (m, search string not found, app title, mb ok) end end //[cf] //[of]:find //[c]Performs a search according to the current find data //[c] //[c]RETURN VALUE //[c] Returns true if the search data is found. //[c] func find (m: frame, first: bool) def win = active window (m) if is nil (win) return false end def data = find data (m) def view = active view (win) def folder = active folder (win) def p1 = cursor (view) def p2 = block (view) def pos = ((direction (data) == find next && ~ first) -> max (p1, p2), min (p1, p2)) def result: local find result if ~ find (data, folder, pos, true, result) return false end show folder (win, folder (result)) def ln = line (position (result)) def col = column (position (result)) // important: active view may have changed when calling show folder select (active view (win), ln, col, ln, col + size (result)) return true end //[cf] //[of]:get selection //[c]Updates the search string with selection. //[c] //[c] If nothing is selected, the methods attempt to find a word under the cursor. //[c] func get selection (m: frame, data: find data) def view = active text view (m) if is nil (view) return end def t := temp string buffer append selection (view, t) set search string (data, as string (t)) compile (data) release (t) end //[cf] //[c] //[of]:open find dialog func open find dialog (m: frame, mode: find mode, replace: bool) def frame = new find box (dialogs (m), m, find data (m), mode, replace) show child ( dialogs (m), start button (frame), cancel find button (frame)) end //[cf] //[of]:start find //[c]Starts the find all operation //[c] public func start find (m: frame, is find in files: bool) def data = find data (m) // get the text file to store search result def output file = open (file database (m), search results name) // create the text object def u := temp string buffer printf (u, str search results, search string (data)) def output = new text object (empty string, as string (u)) release (u) //[c] //[c] Initialize the paramaters //[c] def p : local search process file database (p) = file database (m) data (p) = data output (p) = output root (p) = output count (p) = 0 not replaced count (p) = 0 group by files (p) = ~ follow links (data) && is find in files // 4096 is fine: 16K, upto 4096 folders scanned before first resize. initialize (folders (p), 4096) last reported folder (p) = nil last reported file (p) = nil initialize (pending files (p)) initialize (pending directories (p)) //[c] //[c] Retrieve the initial text file //[c] if is find in files find in files (m, p) else switch start (data) case find in local folder def window = active window (m) if not nil (window) def text file = active text file (m) if not nil (text file) def folder = active folder (window) def aln = absolute line number (folder, first line (folder)) find all (p, text file, folder, aln) end end case find in selection def window = active window (m) def text file = active text file (m) if not nil (window) && not nil (text file) def view = active view (window) if not nil (view) def folder = text (view) def cursor = cursor (view) def block = block (view) if cursor > block def tmp = cursor cursor = block block = tmp end def first line = text line (cursor) def first column = column (cursor) def last line = text line (block) def last column = column (block) def aln = absolute line number (folder, first line) find all ( p, text file, folder, aln, first line, first column, last line, last column) end end else // find in file def text file = active text file (m) if not nil (text file) find all (p, text file) end end end //[c] //[c] Add a summary at the top of the results //[c] def t := temp string buffer add first (output, new empty comment line) def not replaced count = not replaced count (p) if not replaced count > 0 printf (t, str locked occurrences, not replaced count) add first (output, new text line (t, lt comment)) end def count = count (p) if count == 0 t << str search string not found else printf (t, str found occurrences, count) end add first (output, new text line (t, lt comment)) release (t) //[c] //[c] Open the window //[c] // Never an empty text object add (output, new empty comment line) // store result set text (output file, output) // open the window to show search result def w = open window (m, output file) if group by files (p) set layout (w, pbm browser 3) first item (w) enter (w) first item (w) enter (w) else set layout (w, pbm vertical) first item (w) enter (w) end //[c] release (pending directories (p)) release (pending files (p)) release (folders (p)) end //[cf] //[of]:find in files //[c]Starts the find-in-files operation //[c] func find in files (m: frame, p: search process) def data = data (p) def t := temp string buffer full name (directory (data), t) add (pending directories (p), as string (t)) release (t) def subdirectories = subdirectories (data) def patterns : local list of filemasks initialize (patterns, 4) add all (patterns, patterns (data)) def cancel dialog = new cancel find frame (m, style (m), replace (data)) activate (cancel dialog) do modal loop (cancel dialog) ? // update label if ~ is empty (pending files (p)) set progression (cancel dialog, pending files (p) [0], count (p)) end find in directory (p, patterns) if is done (p) close (cancel dialog) end end delete (cancel dialog) release (patterns) end //[cf] //[c] //[of]:goto bookmark func goto bookmark (m: frame, reverse: bool) def win = active window (m) if is nil (win) return false end def result: local find result def found = ~ reverse -> find next bookmark (active folder (win), cursor (active view (win)), result), find previous bookmark (active folder (win), cursor (active view (win)), result) if found show folder (win, folder (result)) def ln = line (position (result)) def col = column (position (result)) // important: active view may have changed when calling show folder select (active view (win), ln, col, ln, col + size (result)) end return found end //[c] //[of]:find next bookmark func find next bookmark ( folder: text object, start: text position, result: find result) def pos : local text position set (pos, start) column (pos) += 1 def limit = nil : text line def found = false repeat def marker = find next marker (folder, pos, mt bookmark) if not nil (marker) def s = start (marker) set (position (result), s) folder (result) = folder size (result) = 0 found = true limit = text line (s) end // go to end of text or first folder def line = text line (pos) while not nil (line) if limit == line return found end if is folder (line) break end line = next (line) end if not nil (line) folder = text object (line) top left position (folder, pos) else while is nil (line) && not nil (parent folder (folder)) line = next (parent line (folder)) folder = parent folder (folder) end if is nil (line) top left position (folder, pos) limit = text line (start) else column (pos) = 0 text line (pos) = line line (pos) = line number (line) end end end return found end //[cf] //[of]:find previous bookmark func find previous bookmark ( folder: text object, start: text position, result: find result) def pos : local text position set (pos, start) def limit = nil : text line def found = false repeat def marker = find previous marker (folder, pos, mt bookmark) if not nil (marker) def s = start (marker) set (position (result), s) folder (result) = folder size (result) = 0 found = true limit = text line (s) end // go to end of text or first folder def line = text line (pos) while not nil (line) if limit == line return found end if is folder (line) break end line = prev (line) end if not nil (line) folder = text object (line) bottom right position (folder, pos) else while is nil (line) && not nil (parent folder (folder)) line = prev (parent line (folder)) folder = parent folder (folder) end if is nil (line) bottom right position (folder, pos) limit = text line (start) else column (pos) = size (line) : int + 1 text line (pos) = line line (pos) = line number (line) end end end return found end //[cf] //[cf] //[of]:find bracket func find bracket (m: frame, select: bool) def win = active window (m) if is nil (win) return false end def view = active view (win) def folder = active folder (win) def pos = cursor (view) def text line = text line (pos) def buf = buf (text line) def col = column (pos) def nesting level = 1 def current = buf [col] def expected: char def backward = false switch current case ${; expected = $} case $}; expected = ${; backward = true case $(; expected = $) case $); expected = $(; backward = true case $[; expected = $] case $]; expected = $[; backward = true else return false end def start folder = folder def start line = line number (pos) def start column = col def limit = size (text line) : int repeat if ~ backward ++ col while col >= limit // get next search line if is folder (text line) folder = text object (text line) text line = first line (folder) else text line = next (text line) // go up if no more lines if is nil (text line) while is nil (text line) && not nil (parent folder (folder)) text line = next (parent line (folder)) folder = parent folder (folder) end end if is nil (text line) return false end end limit = size (text line) : int buf = buf (text line) col = 0 end else -- col while col < 0 // get previous search line text line = prev (text line) if is nil (text line) if not nil (parent folder (folder)) // go up if no more lines text line = parent line (folder) folder = parent folder (folder) else return false end else while is folder (text line) folder = text object (text line) text line = last line (folder) end end buf = buf (text line) col = (size (text line) - 1) : int end end // search in current line def c = buf[col] if c == expected nesting level -= 1 if nesting level == 0 def stop line = line number (text line) def stop column = col if select && start folder == folder if backward def tmp line = start line def tmp col = start column start line = stop line start column = stop column stop line = tmp line stop column = tmp col end stop column += 1 else show folder (win, folder) start line = stop line start column = col + 1 end // important: active view may have changed when calling show folder select (active view (win), start line, start column, stop line, stop column) return true end elsif c == current nesting level += 1 end end return false end //[cf] //[of]:do mark all func do mark all (m: frame) def win = active window (m) if is nil (win) return end def view = active view (win) def folder = active folder (win) def data = find data (m) if size of last match (data) < 2 // minimum length return end // Start from root if scope is current file if scope (data) == find in file folder = root folder (folder) end def pos := top left position (folder) def result: local find result while find (data, folder, pos, false, result) folder = folder (result) def start = position (result) set (pos, start) column (pos) += size (result) // Remove all bookmarks under the selection remove markers (folder, mt match, start, pos) add marker (folder, mt match, start, pos) end end //[cf] //[cf] //[of]:file //[of]:save (text file, filename) //[c]Saves a text file with the given filename //[c] //[c]If the save succeeds, the new filename is assigned to the text file. //[c] //[c]The method contains two hooks for the user preferences file: //[c]- a hook to create the parent directory if it is missing //[c]- a hook to reload settings to get immediate feedback of changes //[c] func save (m: frame, text file: text file, filename: string) : text file error code // Hook 1: we may have to create the directory to save settings if text file == user preference file (m) register config file (application (m), filename) create directories (filename) end def code = save (text file, filename) if not ok (code) show file error (m, last error (text file)) else // Hook 2: save settings => reload settings check settings updates (m) end return code end //[cf] //[of]:save (text file, save as) //[c]Saves a text file //[c] //[c] If 'save as' is set or if the text file has no name assigned yet, the file //[c] selector if opened asking for a filename. //[c] func save (m: frame, text file: text file, save as: bool) // this error code simulates a cancel // i.e. message box not shown, but not ok def code = text file error save def filename = filename (text file) save as |= is empty (filename) if save as def path := temp string buffer append file path (path, filename) def s = file selector (m) save (s) = true title (s) = str save title initial name (s) = empty string initial path (s) = as string (path) if open (s) def fn := temp string buffer get filename (s, fn) code = save (m, text file, as string (fn)) release (fn) end release (path) else code = save (m, text file, filename) end // need to update enabling of save command invalidate local commands (m) return code end //[cf] //[of]:save (save as) //[c]Saves the active text file //[c] func save (m: frame, save as: bool) def text file = active text file (m) if is nil (text file) return text file ok end return save (m, text file, save as) end //[cf] //[of]:try save all //[c]Save all files //[c] //[c] Return Value //[c] The function returns true if and only all modified files are saved //[c] successfully. //[c] func try save all (m: frame) def all successfully saved = true each file (file database (m)) ? text file if is modified (text file) def code = save (m, text file, false) if not ok (code) // remember that save all fails, but continue // anyway. all successfully saved = false end end end return all successfully saved end //[cf] //[of]:close file (text file) public func close file (m: frame, text file: text file) if is modified (text file) def code = ask save (m, text file) if code == id cancel // return without closing return false elsif code == id yes if not ok (save (m, text file, false)) return false end end end if text file == user preference file (m) user preference file (m) = nil end close (file database (m), text file) return true end //[cf] //[c] //[of]:ask save (text file) //[c]Asks to save a file //[c] public func ask save (m: frame, text file: text file) def msg := temp string buffer printf (msg, str file not saved, display filename (text file)) def code = message box (m, as string (msg), app title, mb yes no cancel) release (msg) return code end //[cf] //[of]:ask reload (text file) //[c]Asks to reload a file //[c] public func ask reload (m: frame, text file: text file) def msg := temp string buffer printf (msg, str reload file, display filename (text file)) def code = message box (m, as string (msg), app title, mb yes no) release (msg) return code end //[cf] //[cf] //[of]:window //[of]:open target func open target (m: frame, folder: text object, line: text line) def db = file database (m) def file = find text file (db, folder) def location := open target location (db, file, line) def result = last error (db) if not ok (code (result)) show file error (m, result) return end open window (m, text file (location), folder (location)) end //[cf] //[of]:open window (folder) func open window (m: frame, folder: text object) def file = find text file (file database (m), folder) open window (m, file, folder) end //[cf] //[of]:open window (text file) //[c]Opens a document in a new window //[c] //[c] Empty name opens a new document //[c] func open window (m: frame, text file: text file) return open window (m, text file, text (text file)) end //[cf] //[of]:open window (text file, folder) //[c]Opens a document in a new window //[c] //[c] Empty name opens a new document //[c] func open window (m: frame, text file: text file, folder: text object) // attempt first to recycle the initial window def win = active window (m) if not nil (win) def f = active text file (m) if is nil (f) || not empty (filename (f)) || is modified (f) win = nil end end if is nil (win) win = new code browser window (mdi (m), application (m)) add window (m, win) else invalidate tabs (m) end def app = application (m) def s = settings (app) def mode : paned box mode def conf = find configuration (app, folder) if use default mode (conf) mode = mode (s) else mode = mode (conf) end set layout (win, mode) open (win, text file, folder) set current window (m, win) return win end //[cf] //[of]:open window (filename) //[c]Opens a document in a new window //[c] //[c]Empty name opens a new document //[c] public func open window (m: frame, name: string) return open window (m, name, false) end //[cf] //[of]:open window (filename, create) //[c]Opens a document in a new window //[c] //[c] Empty name opens a new document //[c] public func open window (m: frame, name: string, create: bool) def fdb = file database (m) def text file = open (fdb, name) def last error = last error (fdb) def result = code (last error) // The file is not folded correctly ? if result == unexpected closing folder directive show file error (m, last error) // reopen without handling folding text file = open (fdb, name, true, create) last error = last error (fdb) result = code (last error) end // If the text file does not exist and the create flag is set, // we ask wether the file must be created. if is nil (text file) && result == text file error open && create def msg := temp string buffer printf (msg, str create new file, name) def code = message box (m, as string (msg), app title, mb yes no) release (msg) if code == id no return nil end text file = create (fdb, name) end if not nil (text file) return open window (m, text file) else show file error (m, last error (fdb)) return nil end end //[cf] //[c] //[of]:close window //[c]Closes a window //[c] func close window (m: frame, w: code browser window) // special handling if only one opened window if number of views (mdi (m)) == 1 // never close the untitled window since it can be recycled // (in such a case, open window below would have no effect) def f = current text file (w) if not nil (f) && is empty (filename (f)) && ~ is modified (f) return end // reopen first to avoid loosing focus // (focus is not restored if the multi view looses it) open window (m, empty string) end remove (mdi (m), w) end //[cf] //[c] //[of]:add window //[c]Adds the window to the notebook //[c] func add window (m: frame, w: code browser window) add (mdi (m), w, empty string) end //[cf] //[of]:set current window //[c]Changes the current window //[c] func set current window (m: frame, w: code browser window) set current page (mdi (m), w, true) end //[cf] //[of]:change layout //[c]Change the layout of the active window //[c] func change layout (m: frame, mode: paned box mode) def window = active window (m) if not nil (window) set layout (window, mode) invalidate local commands (m) end end //[cf] //[cf] //[of]:menu //[of]:setup menu (settings) private func setup menu (m: frame, settings: code browser settings) def key mapping = key mapping (settings) if not nil (key mapping) each global command ? cmd def name = name (cmd) def accel = accelerator (key mapping, name) set accelerator (cmd, accel) end end add user defined tools (m, settings) end //[cf] //[of]:add user defined tools (settings) //[c]Adds user defined tools from settings to the "Tools" menu //[c] func add user defined tools (m: frame, settings : code browser settings) def tools menu = tools menu (m) def n = number of tools (settings) if n > 0 set user tool array (m, n) append separator (tools menu) def index = 0 each user tool (settings) ? t def u = user tool commands (m) [index] frame (u) = m tool (u) = t def cmd = new command ( empty string, caption (t), str user tool description, flags (accelerator (t)), key (accelerator (t)), true, false, ^user tool (user tool command), u) command (u) = cmd append menu (m, tools menu, cmd) ++ index end end end //[cf] //[of]:remove user defined tools (settings) //[c]Removes user defined tools from the "Tools" menu //[c] func remove user defined tools (m: frame, settings : code browser settings) // number of static items in tools menu (before tools, and without // separator. equ number of static items = 5 def tools menu = tools menu (m) if number of children (tools menu) > number of static items def i = number of tools (settings) - 1 while i <> -1 def u = user tool commands (m) [i] def cmd = command (u) remove menu (m, tools menu, i+1+number of static items) delete (cmd) i -= 1 end // remove separator remove menu (m, tools menu, number of static items) end end //[cf] //[cf] //[of]:displaying //[of]:show file error (parent box, text file error) //[c]Shows the last file error //[c] public func show file error (parent: frame, e: text file error) def msg := temp string buffer def fn = filename (e) switch code (e) case text file error open printf (msg, str cant open file, fn) case text file error read printf (msg, str error while reading file, fn) case text file error save printf (msg, str cant save file, fn) case text file error write printf (msg, str error while saving file, fn) case unexpected closing folder directive def values: [2] local printf arg values [0].string = fn values [1].dword = line number (e) printf (msg, str unexpected close, values) end def s = as string (msg) if not empty (s) message box (parent, s, str file error, mb ok) end release (msg) end //[cf] //[cf] //[of]:enumerating //[of]:each window //[c]Enumerates all windows //[c] public equ each window (m: frame) each child (mdi (m)) ? page yield (page : code browser window) end end //[cf] //[cf] //[of]:accessing //[of]:active window //[c]Returns the active window //[c] func active window (m: frame) return current page (mdi (m)) : code browser window end //[cf] //[of]:active text file //[c]Returns the active text file //[c] //[c] The active text file is the current text file of the active window. //[c] func active text file (m: frame) def active window = active window (m) if is nil (active window) return nil end return current text file (active window) end //[cf] //[c] //[of]:find data //[c]Returns the find data of the application //[c] func find data (m: frame) return find data (application (m)) end //[cf] //[of]:file database //[c]Returns the file database of the application //[c] func file database (m: frame) return file database (application (m)) end //[cf] //[c] //[of]:invalidate status bar //[c]Invalidates the status bar //[c] //[c] The status bar will be refreshed before re-entering the message loop. //[c] func invalidate status bar (m: frame) valid status bar (m) = false end //[cf] //[of]:invalidate local commands //[c]Invalidates enabling of commands //[c] //[c] The enabling of commands will be updated when re-entering into //[c] the message loop. //[c] func invalidate local commands (m: frame) valid commands (m) = false end //[cf] //[of]:invalidate title //[c]Invalidates the window's title //[c] //[c] The window's title will be update when re-entering into the message loop. //[c] func invalidate title (m: frame) valid title bar (m) = false end //[cf] //[of]:invalidate tabs //[c]Invalidates the tabs' titles //[c] //[c] The tabs will be updated when re-entering into the message loop. //[c] func invalidate tabs (m: frame) valid tabs (m) = false end //[cf] //[c] //[of]:tools menu //[c]Returns the "Tools" menu object //[c] func tools menu (m: frame) return components (m) [tools popup] : menu end //[cf] //[of]:cmd (label) equ cmd (m: frame, l: int) = components (m) [l] : command //[cf] //[c] //[of]:set user tool array (number of tools) //[c] //[c]DESCRIPTION //[c] Resizes the array containing user tool commands. //[c] //[c] This method is also used in the release method to free the //[c] array by just passing 0 as size. //[c] //[c]ARGUMENTS //[c] n: the number of user tools //[c] func set user tool array (m: frame, n: dword) if not nil (user tool commands (m)) free memory (user tool commands (m)) user tool commands (m) = nil end if n > 0 user tool commands (m) = allocate memory (sizeof local user tool command * n) : [] local user tool command end end //[cf] //[of]:set current running tools (tool) func set current running process (m: frame, proc: process, tool: user tool) delete (current running process (m)) delete (current running tool (m)) current running process (m) = proc current running tool (m) = tool set enable (cmd (m, stop running tool command), not nil (tool)) end //[cf] //[cf] //[of]:testing //[of]:can paste reference //[c]Is there a reference to paste //[c] func can paste reference (m: frame) def can paste = false each clipboard format ? f if f == cf text reference (application (m)) // do not return: the iterator must close the clipboard can paste = true break end end return can paste end //[c] //[cf] //[of]:can structure //[c]Returns true if a special object can be inserted into the active text file //[c] //[c] Only languages with comment directives can be structured. //[c] func can structure (m: frame) def text file = active text file (m) if is nil (text file) return false end return can structure (text file) end //[cf] //[cf] //[c] //[of]:private //[of]:paste reference func paste reference (m: frame) def view = active text view (m) if is nil (view) || ~ can structure (m) return false end def done = false each clipboard format ? f if f == cf text reference (application (m)) def t := get clipboard data (f) t << nul char def s = base (t) : string done = paste reference (m, view, s) release (t) end end return done end //[c] func paste reference (m: frame, view: text view, s: string) def text object = text (view) def text file = find text file (file database (m), text object) def base := convert filename to uri (filename (text file)) def uri : local uri initialize (uri, s) resolve relative (uri, base) insert uri (view, uri) release (uri) release (base) return true end //[c] //[c]Sub functions: //[of]:resolve relative (uri, base) //[c] func resolve relative (uri: uri, base: uri) // Find the common base def p = path (uri) def q = path (base) def start = p def last index = 0 repeat def c = p++[] def d = q++[] if c <> d break end if is nul (c) last index = p - 1 - start break end if c == $/ last index = p - start end end // At least one common base: compute relative path if last index > 1 // Go up if required def t := temp string buffer p = path (base) + last index repeat p = first occurrence (p, $/) if is nil (p) break end t << "../" p += 1 end // Append target t << (path (uri) + last index) set path (uri, as string (t)) release (t) end end //[c] //[cf] //[of]:insert uri (view, uri) //[c] func insert uri (view: text view, uri: uri) def t := temp string buffer t << path (uri) def fragment = fragment (uri) if not empty (fragment) t << $# << fragment end if not empty (t) def path = as string (t) insert link (view, empty string, path, path) end release (t) end //[cf] //[cf] //[c] //[of]:check file updates //[c]Find files that have been externally modified and ask for update (depending //[c]on reload mode). //[c] private func check file updates (m: frame) // The method does nothing if reload is disabled def reload mode = reload mode (settings (application (m))) if reload mode == reload never return end // Prevent re-entrance // re-entrance happens when a message box is opened: // the main frame is deactivated, then reactivated and // this method is invoked on activation. if checking file updates (m) return end checking file updates (m) = true each file (file database (m)) ? text file // skip newly created file def last modification = last modification (text file) if last modification <> nil time def time = file last modification (filename (text file)) if time > last modification def code = id yes if reload mode == reload ask || is modified (text file) code = ask reload (m, text file) end if code == id yes def res = incremental reload (text file) if not ok (res) show file error (m, last error (text file)) end end // The last modification time must be updated even if the // load has failed (this prevents infinite reopening of the // reload dialog box). update last modification time (text file) end update read only (text file) end end check settings updates (m) checking file updates (m) = false end //[cf] //[of]:check settings update func check settings updates (m: frame) def a = application (m) def need reload = false each config (a) ? config need reload |= not up to date (config) end if need reload reload settings (m) end end //[cf] //[of]:reload settings //[c]Reloads settings and notify components //[c] //[c]The windows and the frame must be notified in order to reflect changes //[c]and to update pointers to new valid data (old settings are deleted). //[c] //[c]A listener mecanism is not implemented, the listeners are well known //[c]so we can avoid consuming memory and registration/unregistration //[c]process. //[c] private func reload settings (m: frame) def app = application (m) def old settings = settings (app) def new settings = reload settings (app) // notify windows each window (m) ? win settings changed (win, old settings, new settings) end // notify frame settings changed (m, old settings, new settings) // now, nobody should reference anything from old settings, // we can safely delete it delete (old settings) end //[c] private func settings changed ( m: frame, old settings : code browser settings, new settings : code browser settings) remove user defined tools (m, old settings) setup menu (m, new settings) set tab position (mdi (m), tab position (settings (application (m)))) end //[c] //[cf] //[cf] //[cf]