GUI::Editors#
Table of Contents#
NAME#
GUI::Editors
AUTHOR#
Francis Grizzly Smit (grizzly@smit.id.au)
VERSION#
0.1.12
TITLE#
GUI::Editors
SUBTITLE#
A Raku module for managing the users GUI Editor preferences in a variety of programs.
COPYRIGHT#
LGPL V3.0+ LICENSE
Introduction#
A Raku module for managing the users GUI Editor preferences in a variety of programs.
$editor-config#
A constant which contains the location of the users editors file
# the home dir # constant $home = %*ENV<HOME>.Str(); # config files constant $editor-config is export = "$home/.local/share/gui-editors";
NB: the $home
is the value of the users HOME environment variable.
@config-files#
An array containing the configuration files of the program, by default it is set to contain editors the editors configuration file the remainder should be added by init-gui-editors(...)
the initialization procedure for the module.
# The config files to test for # my Str:D @config-files = qw{editors}; sub config-files( --> Array[Str:D]) is export { return @config-files; }
@guieditors#
An array of known GUI editors.
my Str:D @guieditors; sub guieditors( --> Array[Str:D]) is export { return @guieditors; }
grammar Editors & action class EditorsActions#
grammar Editors is BasePaths is export { regex TOP { [ <line> [ \v+ <line> ]* \v* ]? } regex line { [ <white-space-line> || <override-gui_editor> || <config-line> || <editor-to-use> || <comment-line> ] } regex white-space-line { ^^ \h* $$ } regex override-gui_editor { ^^ \h* 'override' \h+ 'GUI_EDITOR' [ \h+ '#' <comment> ]? \h* $$ } regex comment-line { ^^ \h* '#' <-[\v]>* $$ } regex config-line { ^^ \h* 'guieditors' \h* '+'? '=' \h* <editor> \h* [ '#' <comment> \h* ]? $$ } regex editor-to-use { ^^ \h* 'editor' \h* ':'? '=' \h* <editor> \h* [ '#' <comment> \h* ]? $$ } regex editor { <editor-name> || <base-path> <editor-name> } regex comment { <-[\n]>* } token editor-name { <with-other-stuff> } } class EditorsActions does BasePathsActions is export { method white-space-line($/) { my %wspln = type => 'white-space-line', value => ~$/; make %wspln; } method comment-line($/) { my %comln = type => 'comment-line', value => ~$/; make %comln; } #token editor-name { <with-other-stuff> } method editor-name($/) { my $edname = $/<with-other-stuff>.made; make $edname; } method editor($/) { my $ed-name; if $/<base-path> { $ed-name = $/<base-path>.made ~ $/<editor-name>.made; } else { $ed-name = $/<editor-name>.made; } make $ed-name; } method comment($/) { my $comm = (~$/).trim; make $comm; } method config-line($/) { my %cfg-line = type => 'config-line', value => $/<editor>.made; if $/<comment> { my $com = $/<comment>.made; %cfg-line«comment» = $com; } make %cfg-line; } method editor-to-use($/) { my %editor-to-use = type => 'editor-to-use', value => $/<editor>.made; if $/<comment> { my $com = $/<comment>.made; %editor-to-use«comment» = $com; } make %editor-to-use; } method override-gui_editor($/) { my %override-gui_editor = type => 'override-gui_editor', :value; if $/<comment> { my $com = $/<comment>.made; %override-gui_editor«comment» = $com; } make %override-gui_editor; } method line($/) { my %ln; if $/<white-space-line> { %ln = $/<white-space-line>.made; } elsif $/<comment-line> { %ln = $/<comment-line>.made; } elsif $/<config-line> { %ln = $/<config-line>.made; } elsif $/<editor-to-use> { %ln = $/<editor-to-use>.made; } elsif $/<override-gui_editor> { %ln = $/<override-gui_editor>.made; } make %ln; } method TOP($made) { my @top = $made<line>».made; $made.make: @top; } } # class EditorsActions does BasePathsActions is export #
grammar EditorLine & class EditorLineActions#
A grammar and associated action class to parse and recognise the editor := value # comment
lines in the editors file.
grammar EditorLine is BasePaths is export { regex TOP { ^ \h* 'editor' \h* ':'? '=' \h* <editor> \h* [ '#' <comment> \h* ]? $ } regex editor { <editor-name> || <base-path> <editor-name> } regex comment { <-[\n]>* } token editor-name { <with-other-stuff> } } class EditorLineActions does BasePathsActions is export { #token editor-name { <with-other-stuff> } method editor-name($/) { my $edname = $/<with-other-stuff>.made; make $edname; } method editor($/) { my $ed-name; if $/<base-path> { $ed-name = $/<base-path>.made ~ '/' ~ $/<editor-name>.made; } else { $ed-name = $/<editor-name>.made; } make $ed-name; } method comment($/) { my $comm = (~$/).trim; make $comm; } method config-line($/) { my %cfg-line = type => 'config-line', value => $/<editor>.made; if $/<comment> { my $com = $/<comment>.made; %cfg-line«comment» = $com; } make %cfg-line; } method TOP($made) { my %top = type => 'editor-to-use', value => $made<editor>.made; if $made<comment> { my $com = $made<comment>.made; %top«comment» = $com; } $made.make: %top; } } # class EditorLineActions does BasePathsActions is export #
grammar OverrideGUIEditor & actions class OverrideGUIEditorActions#
A grammar to parse/recognise the override GUI_EDITOR # comment
line.
grammar OverrideGUIEditor is export { regex TOP { ^ \h* [ <commented> \h* ]? 'override' \h+ 'GUI_EDITOR' [ \h+ '#' <comment> ]? \h* $ } regex comment { <-[\n]>* } token commented { '#' } } class OverrideGUIEditorActions is export { method comment($/) { my $comment = (~$/).trim; make $comment; } method commented($/) { my $commented = (~$/).trim; make $commented; } method TOP($made) { my %top = type => 'override-gui_editor', :value; if $made<commented> { %top«value» = False; } if $made<comment> { my $com = $made<comment>.made; %top«comment» = $com; } $made.make: %top; } } # class OverrideGUIEditorActions #
Some useful variables#
NB: All these variables are available outside of the module as a sub of the same name. That way I can give read only access to them.
$GUI_EDITOR#
The value of the %*ENV«GUI_EDITOR»
environment variable or ''
if not set.
$VISUAL#
The value of the %*ENV«VISUAL»
environment variable or ''
if not set.
$EDITOR#
The value of the %*ENV«EDITOR»
environment variable or ''
if not set.
my Str:D $GUI_EDITOR = ((%*ENV<GUI_EDITOR>:exists) ?? ~%*ENV<GUI_EDITOR> !! ''); my Str:D $VISUAL = ((%*ENV<VISUAL>:exists) ?? ~%*ENV<VISUAL> !! ''); my Str:D $EDITOR = ((%*ENV<EDITOR>:exists) ?? ~%*ENV<EDITOR> !! ''); sub GUI_EDITOR( --> Str:D) is export { return $GUI_EDITOR; } sub VISUAL( --> Str:D) is export { return $VISUAL; } sub EDITOR( --> Str:D) is export { return $EDITOR; }
@GUIEDITORS#
The Array of Hashes that the Editors
grammar and EditorsActions
generate from parsing the editors file.
@gui-editors#
The Array of GUI Editors defined in the editors file.
@default-editors#
The array of editors selected in the file should have only one element otherwise the file is miss configured.
my Hash @GUIEDITORS; my Str:D @gui-editors; my Str:D @default-editors; sub GUIEDITORS( --> Array[Hash]) is export { return @GUIEDITORS; } sub gui-editors( --> Array[Str:D]) is export { return @gui-editors; } sub default-editors( --> Array[Str:D]) is export { return @default-editors; }
@override-gui_editor#
An array of True values one for each of the times the override GUI_EDITOR
directive appears in the editors file, it is an error for it to appear more than once, (it's a zero or one rule).
$override-GUI_EDITOR#
True if the override GUI_EDITOR
directive is present in the editors file. If True then the setting in the file overrides the %*ENV«GUI_EDITOR»
variable, otherwise %*ENV«GUI_EDITOR»
wins.
my Bool:D @override-gui_editor; sub override-gui_editor( --> Array[Bool:D]) is export { return @override-gui_editor; } my Bool:D $override-GUI_EDITOR = False; sub override-GUI_EDITOR( --> Bool:D) is export { return $override-GUI_EDITOR; }
In init-gui-editors
#
sub init-gui-editors(Str:D @client-config-files, Str:D $client-config-path, &gen-configs:(Str:D, Str:D --> Bool:D), &check:(Str:D @cfg-files, Str:D $config --> Bool:D) --> Bool:D) is export
...
...
...
@GUIEDITORS = Editors.parse(@editors-file.join("\x0A"), :enc('UTF-8'), :$actions).made; @gui-editors = @GUIEDITORS.grep( -> %l { %l«type» eq 'config-line' } ).map: -> %ln { %ln«value»; }; @default-editors = @GUIEDITORS.grep( -> %l { %l«type» eq 'editor-to-use' } ).map: -> %ln { %ln«value»; }; if @default-editors > 1 { $*ERR.say: "Error: file $editor-config/editors is miss configured more than one editor defined should be 0 or 1"; } @override-gui_editor = @GUIEDITORS.grep( -> %l { %l«type» eq 'override-gui_editor' } ).map: -> %ln { %ln«value»; }; if @override-gui_editor > 1 { my Int:D $elems = @override-gui_editor.elems; $*ERR.say: qq[Make up your mind only one "override GUI_EDITOR" is required, you supplied $elems are you insane???]; $override-GUI_EDITOR = True; } elsif @override-gui_editor == 1 { $override-GUI_EDITOR = True; } if @gui-editors { #@gui-editors.raku.say; for @gui-editors -> $geditor { if !@guieditors.grep: { $geditor } { my Str $guieditor = $geditor; $guieditor .=trim; @guieditors.append($guieditor); } } } if $override-GUI_EDITOR && @default-editors { $editor = @default-editors[@default-editors - 1]; }elsif %*ENV<GUI_EDITOR>:exists { my Str $guieditor = ~%*ENV<GUI_EDITOR>; if ! @guieditors.grep( { $_ eq $guieditor.IO.basename } ) { @guieditors.prepend($guieditor.IO.basename); } } elsif $editor-guessed && @default-editors { $editor = @default-editors[@default-editors - 1]; }
$editor#
The editor the user has chosen.
# the editor to use # my Str:D $editor = ''; sub editor( --> Str:D) is export { return $editor; }
edit-configs()#
A function to open the users configuration files in their chosen editor.
sub edit-configs() returns Bool:D is export { if $editor { my $option = ''; my @args; my $edbase = $editor.IO.basename; if $edbase eq 'gvim' { $option = '-p'; @args.append('-p'); } for @config-files -> $file { if $file eq 'editors' { @args.append("$editor-config/$file"); } else { @args.append("$client-config/$file"); } } my $proc = run($editor, |@args); return $proc.exitcode == 0 || $proc.exitcode == -1; } else { $*ERR.say: "no editor found please set GUI_EDITOR, VISUAL or EDITOR to your preferred editor."; $*ERR.say: "e.g. export GUI_EDITOR=/usr/bin/gvim"; $*ERR.say: "or set editor in the $editor-config/editors file this can be done with the set editor command."; $*ERR.say: qq[NB: the editor will be set by first checking GUI_EDITOR then VISUAL then EDITOR and finally editor in the config file so GUI_EDITOR will win over all. Unless you supply the "override GUI_EDITOR" directive in the $editor-config/editors file and also supplied the "editor := <editor>" directive]; return False; } }
Editor functions#
list-editors(…)#
List all known GUI Editors, flagging the selected editor with '*' note if none is flagged either $editor
is set to a non GUI Editor or $editor
is set to the empty string.
sub list-editors(Str:D $prefix, Bool:D $colour, Bool:D $syntax, Int:D $page-length, Regex:D $pattern --> Bool) is export
editors-stats(…)#
Show the values of some editors parameters.
sub editors-stats(Str:D $prefix, Bool:D $colour, Bool:D $syntax, Int:D $page-length, Regex:D $pattern --> Bool) is export
BadEditor#
BadEditor
is an Exception class for the GUI::Editors
module.
class BadEditor is Exception is export { has Str:D $.msg = 'Error: bad editor specified'; method message( --> Str:D) { $!msg; } }
set-editor(…)#
A function to set the editor of choice.
sub set-editor(Str:D $editor, Str $comment = Str --> Bool:D) is export
NB: this will still be overridden by %*ENV«GUI_EDITOR»
unless you set override GUI_EDITOR.
add-gui-editor(…)#
Add an editor to the list of known GUI Editors.
sub add-gui-editor(Str:D $editor, Str $comment = Str --> Bool:D) is export
NB: please make sure it really is a GUI Editor otherwise this module will not work correctly. You are completely free to set the chosen editor to what ever you like.
set-override-GUI_EDITOR(…)#
Set or unset the override GUI_EDITOR flag.
sub set-override-GUI_EDITOR(Bool:D $value, Str $comment = Str --> Bool:D) is export
If set then the file always wins else %*ENV«GUI_EDITOR»
always wins if set.
backup-editors(…)#
Backup the editors file.
sub backup-editors(Bool:D $use-windows-formatting --> Bool) is export
NB: if $use-windows-formatting is true or the program is running on windows then .
will become ·
and :
will become .
, this is to avoid problems with the special meaning of :
on windows.
restore-editors(…)#
Restore the editors file from a backup.
sub restore-editors(IO::Path $restore-from --> Bool) is export
If $restore-from
is relative and not found from the current directory $editor-config/$restore-from
will be tried.
list-editors-backups(…)#
List all the available backups in the $editor-config
.
sub list-editors-backups(Str:D $prefix, Bool:D $colour is copy, Bool:D $syntax, Regex:D $pattern, Int:D $page-length --> Bool:D) is export
Where
$prefix
a filter only files starting with this are included in the result.$colour
colour the output.$syntax
syntax highlight the results colour on steroids.$pattern
a regex to filter the results by only files matching this will be included in the results.$page-length
set the length of the pages before it repeats the header.
backups-menu-restore-editors(…)#
Presents a menu so you can choose which backup to restore from.
sub backups-menu-restore-editors(Bool:D $colour, Bool:D $syntax, Str:D $message = "" --> Bool:D) is export
Where:
$colour
ifTrue
represents the menu in colours.$syntax
ifTrue
represents the menu syntax highlighted.basically colour on steroids.
- uses the
Gzz::Text::Utils::menu(…)
, which uses theGzz::Text::Utils::dropdown(…)
function for colour and syntax.
- uses the
edit-files(…)#
Edit arbitrary files using chosen editor.
sub edit-files(Str:D @files --> Bool:D) is export
Where
@files
a list of files to open in the chosen GUI editor.