Raku filetype highlighter (know previously as Perl6)

A start at *.raku filetype highlighters. Chipping away locally and not all setup yet. So, I’m able to share through this platform rather than a repo at the moment. Anyone looking to or wanting a bit of colour for their Raku files just drop it in/as autoload/raku.kak and hackity hack hack.

raku.kak
# https://www.raku.org/
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Adapted from source:
#    <https://github.com/hankache/raku.nanorc>
#

# Detection
# ‾‾‾‾‾‾‾‾‾

hook global BufCreate .*\.raku(mod|doc|test)?$ %{
    set-option buffer filetype raku
}

# Initialization
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾

hook global WinSetOption filetype=raku %{
    require-module raku

    set-option window static_words %opt{raku_static_words}

    # cleanup trailing whitespaces when exiting insert mode
    hook window ModeChange pop:insert:.* -group raku-trim-indent %{ try %{ execute-keys -draft xs^\h+$<ret>d } }
    hook window InsertChar \n -group raku-insert raku-insert-on-new-line
    hook window InsertChar \n -group raku-indent raku-indent-on-new-line
    hook window InsertChar \{ -group raku-indent raku-indent-on-opening-curly-brace
    hook window InsertChar \} -group raku-indent raku-indent-on-closing-curly-brace

    hook -once -always window WinSetOption filetype=.* %{ remove-hooks window raku-.+ }
}

hook -group raku-highlight global WinSetOption filetype=raku %{
    add-highlighter window/raku ref raku
    hook -once -always window WinSetOption filetype=.* %{ remove-highlighter window/raku }
}

provide-module raku %§

# Highlighters
# ‾‾‾‾‾‾‾‾‾‾‾‾

add-highlighter shared/raku regions
add-highlighter shared/raku/code default-region group
add-highlighter shared/raku/dquote region %{(?<!')"} %{(?<!\\)(\\\\)*"} group
add-highlighter shared/raku/squote region %{'} %{(?<!\\)'} group

# Comments - single line
add-highlighter shared/raku/comment_line region %{#(?![|=])} %{$} fill comment

# Pod Declarator block/single line
add-highlighter shared/raku/pod_block region %{^=begin [A-Za-z0-9]*?} %{^=end [A-Za-z0-9]*?} fill documentation
add-highlighter shared/raku/pod_line  region %{#(?=[|=])} %{$} fill documentation

# Heredocs
add-highlighter shared/raku/heredocs region -match-capture %{qq?:to/END/;} %{^END} fill string

# Double quoted strings
add-highlighter shared/raku/dquote/ fill string
add-highlighter shared/raku/dquote/ regex \{.*?\} 0:function

# Single quoted strings
add-highlighter shared/raku/squote/ fill string

# Discolour loading a modules FQN
add-highlighter shared/raku/code/ regex %{^(use|need|import)(?S)(.+);$} 2:default+fa

# Variables
add-highlighter shared/raku/code/ regex %{[$@%&](\.|!|\^)?([A-Za-z]|_)} 0:variable
add-highlighter shared/raku/code/ regex %{[$@%&](\.|!|\^)?([A-Za-z]|_)([A-Za-z0-9]|-|_)*([A-Za-z0-9]|_)} 0:variable
add-highlighter shared/raku/code/ regex %{[$@%&](\?|\*)([A-Z])([A-Z]|-)*([A-Z])} 0:variable

# Angle brackets
add-highlighter shared/raku/code/ regex %{<([A-Za-z0-9]|-| |\.|_|/)*>} 0:default
add-highlighter shared/raku/code/ regex %{\$<([A-Za-z0-9]|-|_)*>} 0:default
add-highlighter shared/raku/code/ regex %{(<|>)} 0:default

# Versions
add-highlighter shared/raku/code/ regex %{\b(v([0-9]|\*)(\.([A-Za-z0-9]|\*))*)\b} 0:default

# Sym
add-highlighter shared/raku/code/ regex %{:sym} 0:attribute

#Regex
add-highlighter shared/raku/code/ regex %{(?S)(m|rx|tr|TR|s|S)?/.*/} 0:attribute

#Regex Match
add-highlighter shared/raku/code/ regex %{\$/} 0:builtin

# Numbers
add-highlighter shared/raku/code/ regex %{\b([0-9]+)\b} 0:value
add-highlighter shared/raku/code/ regex %{\b([0-9]*(\.|_)[0-9]+)\b} 0:value
add-highlighter shared/raku/code/ regex %{\b([0-9]+(e)[0-9]+)\b} 0:value
add-highlighter shared/raku/code/ regex %{\b([0-9]*(\+)*([0-9]|NaN\\|Inf\\)+i)\b} 0:value

#Nativecall types
add-highlighter shared/raku/code/ regex %{\b(int8|int16|int32|int64|uint8|uint16|uint32|uint64|long|longlong|num32|num64|size_t|bool|CArray|Pointer)\b} 0:type

# Traits
add-highlighter shared/raku/code/ regex %{\b(rw|required|native|repr|export|symbol)\b} 0:keyword

# Booleans
add-highlighter shared/raku/code/ regex %{\b(True|False)\b} 0:builtin

# Ops
add-highlighter shared/raku/code/ regex %{\b(eq|ne|gt|lt|le|ge|div|gcd|lcm|leg|cmp|ff)\b} 0:operator
add-highlighter shared/raku/code/ regex %{\b(=|=>|==|!=|<|>|<=|>=|\+|\*|-|/|~|\*\*|%|%%|<=>|~~|\+\+|--|\?|!|\.\.|\.\.\^|\^\.\.|\^\.\.\^|\^|\.\.\.|\||\.)\b} 0:operator

add-highlighter shared/raku/code/ regex %{\b(infix:<[+-]>)\b} 0:function

# Grammar
evaluate-commands %sh{
    # Exceptions
    exceptions="X::AdHoc X::Anon::Augment X::Anon::Multi X::Assignment::RO X::Attribute::NoPackage
                X::Attribute::Package X::Attribute::Undeclared X::Augment::NoSuchType X::Bind
                X::Bind::NativeType X::Bind::Slice X::Caller::NotDynamic X::Channel::ReceiveOnClosed
                X::Channel::SendOnClosed X::Comp X::Composition::NotComposable X::Constructor::Positional
                X::ControlFlow X::ControlFlow::Return X::DateTime::TimezoneClash X::Declaration::Scope
                X::Declaration::Scope::Multi X::Does::TypeObject X::Eval::NoSuchLang X::Export::NameClash
                X::Inheritance::NotComposed X::Inheritance::Unsupported X::IO X::IO::Chdir X::IO::Chmod
                X::IO::Copy X::IO::Cwd X::IO::Dir X::IO::DoesNotExist X::IO::Link X::IO::Mkdir X::IO::Move
                X::IO::Rename X::IO::Rmdir X::IO::Symlink X::IO::Unlink X::Method::InvalidQualifier
                X::Method::NotFound X::Method::Private::Permission X::Method::Private::Unqualified
                X::Mixin::NotComposable X::NoDispatcher X::Numeric::Real X::NYI X::Obsolete X::OS
                X::OutOfRange X::Package::Stubbed X::Parameter::Default X::Parameter::MultipleTypeConstraints
                X::Parameter::Placeholder X::Parameter::Twigil X::Parameter::WrongOrder X::Phaser::Multiple
                X::Phaser::PrePost X::Placeholder::Block X::Placeholder::Mainline X::Pod X::Proc::Async
                X::Proc::Async::AlreadyStarted X::Proc::Async::CharsOrBytes X::Proc::Async::MustBeStarted
                X::Proc::Async::OpenForWriting X::Proc::Async::TapBeforeSpawn X::Proc::Unsuccessful
                X::Promise::CauseOnlyValidOnBroken X::Promise::Vowed X::Redeclaration X::Role::Initialization
                X::Seq::Consumed X::Sequence::Deduction X::Signature::NameClash X::Signature::Placeholder
                X::Str::Numeric X::StubCode X::Syntax X::Syntax::Augment::WithoutMonkeyTyping
                X::Syntax::Comment::Embedded X::Syntax::Confused X::Syntax::InfixInTermPosition
                X::Syntax::Malformed X::Syntax::Missing X::Syntax::NegatedPair X::Syntax::NoSelf
                X::Syntax::Number::RadixOutOfRange X::Syntax::P5 X::Syntax::Regex::Adverb
                X::Syntax::Regex::SolitaryQuantifier X::Syntax::Reserved X::Syntax::Self::WithoutObject
                X::Syntax::Signature::InvocantMarker X::Syntax::Term::MissingInitializer X::Syntax::UnlessElse
                X::Syntax::Variable::Match X::Syntax::Variable::Numeric X::Syntax::Variable::Twigil
                X::Temporal X::Temporal::InvalidFormat X::TypeCheck X::TypeCheck::Assignment X::TypeCheck::Binding
                X::TypeCheck::Return X::TypeCheck::Splice X::Undeclared"

    # Keywords
    keywords="my our class role grammar is does sub method submethod try CATCH default when if
              elsif else unless with orwith without for given proceed succeed loop while until
              repeat module use need import require unit constant enum multi return has token
              rule make made proto state augment but anon supersede let subset gather returns
              return-rw"

    # Methods
    methods="ACCEPTS ASSIGN-KEY ASSIGN-POS AT-KEY AT-POS Array BIND-KEY BIND-POS Bag BagHash Bool
             Bridge CALL-ME CREATE Capture Channel Complex DELETE-KEY DELETE-POS DESTROY DISTROnames
             Date DateTime EVAL EXISTS-KEY EXISTS-POS Hash IO IO::Notification.watch-path Instant
             Int KERNELnames List Map Mix MixHash NFC NFD NFKC NFKD Num Numeric Promise Rat Real
             SPEC Set SetHash Slip Str Supply VMnames WHERE WHEREFORE WHICH WHY abs abs2rel absolute
             accept accessed acquire act action actions add add_attribute add_enum_value add_fallback
             add_method add_parent add_private_method add_role add_trustee adverb after all allocate
             allof allowed alternative-names annotations antipair antipairs any anyof app_lifetime
             append arch archname args arity assuming ast at attributes auth backtrace base base-repeating
             basename batch bind-stderr bind-stdin bind-stdout bind-udp bits bless block bool-only
             bounds break broken build-date bytes cache calling-package can cancel candidates cando
             canonpath caps caption capture catdir categorize categorize-list catfile catpath cause
             ceiling changed channel chdir child child-name child-typename chmod chomp chunks classify
             classify-list cleanup clone close close-stdin closed code codes collate column comb
             combinations command comment compiler compose compose_type composer condition config
             configure_destroy configure_type_checking conj connect constraints construct contains
             contents copy count count-only cpu-cores cpu-usage create_type cue curdir curupdir d
             day day-of-month day-of-week day-of-year daycount days-in-month declaration decode
             decoder deepmap default defined delayed denominator desc destroyers devnull did-you-mean
             dir-sep dirname do does done duckmap dynamic e eager earlier elems emit enclosing encode
             encoder encoding end ends-with enum_from_value enum_value_list enum_values enums eof
             exception excludes-max excludes-min exitcode exp expected extension f fail feature file
             filename find_method find_method_qualified finish first flat flatmap floor flush fmt
             format formatter freeze from from-list from-loop from-posix full get get_value getc
             gist got grab grabpairs grep handle handled handles hardware has_accessor hash head
             headers hh-mm-ss hidden hides hour how hyper id illegal im in in-timezone indent indices
             infinite infix install_method_cache instead int-bounds interval invalid-str invert
             invocant is-absolute is-hidden is-initial-thread is-int is-lazy is-leap-year is-relative
             is-routine is-setting is-win isNaN is_trusted is_type isa item iterator join keep kept
             key keyof keys kill kv kxxv l lang last later lazy leading level line lines link list
             listen live local lock lookup lsb made make map match max maxpairs merge message method
             method_table methods migrate min minmax minpairs minute misplaced mode modified month
             move msb multi multiness my name named named_names narrow native-descriptor new
             new-from-daycount new-from-pairs new_type next next-handle nl-in nl-out nodemap none
             norm not note now nude numerator of offset offset-in-hours offset-in-minutes old
             on-close on-switch one open opened operation optional ords orig os-error osname
             out-buffer package package-kind package-name packages pair pairs pairup parameter params
             parent parent-name parents parse parsefile parts path path-sep payload peer-host peer-port
             perl permutations phaser pick pickpairs pid placeholder plus polar poll polymod pop pos
             positional posix postfix postmatch precomp-ext precomp-target pred prefix prematch prepend
             print print-nl print-to printf private private_method_table proc produce promise protect
             pull-one push push-all push-at-least push-exactly push-until-lazy put qualifier-type
             quit r race radix rand range raw re read readchars readonly ready reallocate reals reason
             rebless receive recv redispatcher redo reduce rel2abs relative release rename repeated
             replacement reserved resolve restore result resume rethrow reverse right role roles_to_compose
             rolish roll rootdir roots rotor round routine-type run rwx s say schedule-on scheduler
             scope sec second seek self send set-instruments set_hidden set_name set_package set_rw
             set_value setup_finalization shape share shell shift sibling sigil sign signal signals
             signature sink sink-all skip skip-at-least skip-at-least-pull-one skip-one slurp slurp-rest
             slurpy so socket-host socket-port sort source source-package spawn splice split splitdir
             splitpath spurt sqrt squish stable start started starts-with status stderr stdout sub_signature
             subbuf subbuf-rw subname subparse subst subst-mutate substr-eq substr-rw succ sum symlink
             t tail take tap target target-name tell then throttle throw timezone tmpdir to to-posix
             today toggle total trailing trans tree trim trim-leading trim-trailing truncate truncated-to
             trusts try_acquire trying twigil type type_captures typename udp uncaught_handler unimatch
             uniname uninames uniprop uniprops unique unival univals unlink unlock unpack unpolar unshift
             unwrap updir utc value values variable verbose-config version volume vow w wait watch watch-path
             week week-number week-year weekday-of-month what when whole-second words workaround wrap write
             write-to x yada year yield yyyy-mm-dd z zip zip-latest WHAT WHO HOW DEFINITE VAR mro BUILD"

    # Phasers
    phasers="BEGIN CHECK INIT END CLOSE ENTER LEAVE KEEP UNDO PRE POST FIRST NEXT LAST CATCH CONTROL QUIT DOC"

    # Pragmas
    pragmas="MONKEY-SEE-NO-EVAL MONKEY-TYPING MONKEY-GUTS MONKEY experimental fatal lib newline nqp"

    # Subs
    subroutines="Bool EVALFILE MAIN T USAGE abs acos acosec acosech acosh acotan acotanh asec asech asin
                 asinh atan atan2 atanh atomic-assign atomic-dec-fetch atomic-fetch atomic-fetch-add
                 atomic-fetch-dec atomic-fetch-inc atomic-fetch-sub atomic-inc-fetch await bag callframe
                 callsame callwith cas categorize ceiling cglobal chars chdir chmod chomp chop chr chrs
                 cis classify codes comb combinations cos cosec cosech cosh cotan cotanh cross defined
                 die dir elems end exit exp explicitly-manage expmod fc first flat flip floor full-barrier
                 gist grep index indir is-prime item join keys kv lastcall lc lines
                 log log10 map mix mkdir nativecast nativesizeof nextcallee nextsame nextwith open ord
                 ords pack pairs parse-base parse-names periods permutations pick pop print produce prompt
                 push put rand reduce repeated report reverse rindex rmdir roll roots rotate round roundrobin
                 run samecase samemark samewith say sech set shell shift signal sin sinh sleep sleep-timer
                 sleep-until slip slurp snap snapper sort splice split sprintf spurt sqrt squish srand
                 subbuf-rw substr sum take take-rw tan tanh tc tclc trim trim-leading trim-trailing truncate
                 uc uniparse unique unival unshift val values warn wordcase words zip"

    # Test Module
    tests="plan done-testing bail-out todo skip skip-rest diag subtest pass flunk ok nok cmp-ok
           is-deeply isnt is-approx like unlike use-ok isa-ok does-ok can-ok dies-ok lives-ok
           eval-dies-ok eval-lives-ok throws-like fails-like"

    # Types
    types="Any Array Associative AST atomicint Attribute Backtrace Backtrace::Frame Bag Baggy BagHash
           Blob Block Bool Buf Callable CallFrame Cancellation Capture Channel Code compiler Complex
           ComplexStr Cool CurrentThreadScheduler Cursor Date Dateish DateTime Distro Duration Encoding
           Exception Failure FatRat Grammar Hash HyperWhatever Instant Int IntStr IO IO::ArgFiles
           IO::CatHandle IO::Handle IO::Notification IO::Path IO::Path::Cygwin IO::Path::QNX IO::Path::Unix
           IO::Path::Win32 IO::Pipe IO::Socket IO::Socket::Async IO::Socket::INET IO::Spec IO::Spec::Cygwin
           IO::Spec::QNX IO::Spec::Unix IO::Spec::Win32 IO::Special Iterable Iterator Junction Kernel
           Label List Lock Lock::Async Macro Map Match Metamodel::AttributeContainer Metamodel::C3MRO
           Metamodel::ClassHOW Metamodel::EnumHOW Metamodel::Finalization Metamodel::MethodContainer
           Metamodel::MROBasedMethodDispatch Metamodel::MultipleInheritance Metamodel::Naming
           Metamodel::Primitives Metamodel::PrivateMethodContainer Metamodel::RoleContainer
           Metamodel::Trusting Method Mix MixHash Mixy Mu NFC NFD NFKC NFKD Nil Num Numeric NumStr
           ObjAt Order Pair Parameter Perl Pod::Block Pod::Block::Code Pod::Block::Comment
           Pod::Block::Declarator Pod::Block::Named Pod::Block::Para Pod::Block::Table Pod::Heading
           Pod::Item Positional PositionalBindFailover Proc Proc::Async Promise Proxy PseudoStash
           QuantHash Range Rat Rational RatStr Real Regex Routine Scalar Scheduler Semaphore Seq Set
           SetHash Setty Signature Slip Stash Str StrDistance Stringy Sub Submethod Supplier
           Supplier::Preserving Supply Systemic Tap Telemetry Telemetry::Instrument::Thread
           Telemetry::Instrument::Usage Telemetry::Period Telemetry::Sampler Thread ThreadPoolScheduler
           UInt Uni utf8 Variable Version VM Whatever WhateverCode WrapHandle int uint num str"

    join() { sep=$2; eval set -- $1; IFS="$sep"; echo "$*"; }

    # Add the language's grammar to the static completion list
    printf %s\\n "declare-option str-list raku_static_words $(join "${exceptions} ${keywords} ${methods} ${phasers} ${pragmas} ${subroutines} ${tests} ${types}" ' ')"

    # Highlight keywords
    printf %s "
        add-highlighter shared/raku/code/ regex \b($(join "${exceptions}" '|'))\b 0:default
        add-highlighter shared/raku/code/ regex \b($(join "${keywords}" '|'))\b 0:keyword
        add-highlighter shared/raku/code/ regex \b($(join "${methods}" '|'))\b 0:function
        add-highlighter shared/raku/code/ regex \b($(join "${phasers}" '|'))\b 0:function
        add-highlighter shared/raku/code/ regex \b($(join "${pragmas}" '|'))\b 0:function
        add-highlighter shared/raku/code/ regex \b($(join "${subroutines}" '|'))\b 0:function
        add-highlighter shared/raku/code/ regex \b($(join "${tests}" '|'))\b 0:default+u
        add-highlighter shared/raku/code/ regex \b($(join "${types}" '|'))\b 0:type
    "
}

# Commands
# ‾‾‾‾‾‾‾‾

define-command -hidden raku-insert-on-new-line %~
    evaluate-commands -draft -itersel %=
        # copy # comments prefix and following white spaces
        try %{ execute-keys -draft <semicolon><c-s>kx s ^\h*\K#\h* <ret> y<c-o>P<esc> }
    =
~

define-command -hidden raku-indent-on-new-line %~
    evaluate-commands -draft -itersel %=
        # preserve previous line indent
        try %{ execute-keys -draft <semicolon>K<a-&> }
        # indent after lines ending with { or (
        try %[ execute-keys -draft kx <a-k> [{(]\h*$ <ret> j<a-gt> ]
        # cleanup trailing white spaces on the previous line
        try %{ execute-keys -draft kx s \h+$ <ret>d }
        # align to opening paren of previous line
        try %{ execute-keys -draft [( <a-k> \A\([^\n]+\n[^\n]*\n?\z <ret> s \A\(\h*.|.\z <ret> '<a-;>' & }
        # indent after a switch's case/default statements
        try %[ execute-keys -draft kx <a-k> ^\h*(case|default).*:$ <ret> j<a-gt> ]
        # indent after if|else|while|for
        try %[ execute-keys -draft <semicolon><a-F>)MB <a-k> \A(if|else|while|for)\h*\(.*\)\h*\n\h*\n?\z <ret> s \A|.\z <ret> 1<a-&>1<a-,><a-gt> ]
        # deindent closing brace(s) when after cursor
        try %[ execute-keys -draft x <a-k> ^\h*[})] <ret> gh / [})] <ret> m <a-S> 1<a-&> ]
    =
~

define-command -hidden raku-indent-on-opening-curly-brace %[
    # align indent with opening paren when { is entered on a new line after the closing paren
    try %[ execute-keys -draft -itersel h<a-F>)M <a-k> \A\(.*\)\h*\n\h*\{) <ret> s \A|.\z <ret> 1<a-&> ]
]

define-command -hidden raku-indent-on-closing-curly-brace %[
    # align to opening curly brace when alone on a line
    try %[ execute-keys -itersel -draft <a-h><a-k>^\h+\}$<ret>hms\A|.\z<ret>1<a-&> ]
]

§

Raku highlighter screenshot with a solarized-dark editor colour scheme: