diff --git a/debian/changelog b/debian/changelog index 3ad13a0..cec5546 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,19 @@ +lite-xl (2.1.8-4) stonking; urgency=medium + + * Bundle a curated set of community plugins (vendored, pinned in + debian/extra/README.source): + - gitstatus, gitopen, fontconfig, open_ext, select_colorscheme, + smoothcaret, nerdicons (+ Symbols Nerd Font Mono, font path patched + to DATADIR) + - lite-xl-lsp (full LSP client; activates when a language server is + configured) with the lite-xl-widgets library it requires + - 104 additional language syntax plugins (none duplicate the nine + already bundled with core) + * settings GUI plugin left out: its hard dependency on a widget that is + missing from lite-xl-widgets@master makes it fail to load upstream. + + -- Valentin Haudiquet Wed, 16 Sep 2026 22:10:00 +0200 + lite-xl (2.1.8-3) stonking; urgency=medium * Ship a VSCode-style dark theme and out-of-the-box config: diff --git a/debian/extra/README.source b/debian/extra/README.source new file mode 100644 index 0000000..d88cd2c --- /dev/null +++ b/debian/extra/README.source @@ -0,0 +1,20 @@ +Vendored from upstream, pinned by commit: + +- lite-xl-plugins https://github.com/lite-xl/lite-xl-plugins @ 31eef29 (master, 2026-09) + plugins/: gitstatus, gitopen, fontconfig, open_ext, select_colorscheme, + smoothcaret, nerdicons, language_* (all 104; none overlap the ones bundled + in the core data/ directory) +- lite-xl-lsp https://github.com/lite-xl/lite-xl-lsp @ d1432ae (master, 2026-09) + vendored whole as plugins/lsp/ (screenshots removed) +- lite-xl-widgets https://github.com/lite-xl/lite-xl-widgets @ dcf1c8c + NOT vendored: only the settings plugin needs it, and settings@master + requires libraries.widget.fonts which does not exist in the widgets + repository at any revision, so settings cannot load. Revisit when + upstream publishes the missing widget. +- nerdicons font mapping: plugins/font_symbols_nerdfont_mono_regular.lua + shipped as usr/share/lite-xl/libraries/font_symbols_nerdfont_mono_regular.lua + with the font path patched from USERDIR to DATADIR, plus the + Symbols Nerd Font Mono TTF (SIL OFL 1.1) next to it. + +Refresh by re-cloning the sources at a new commit and re-applying the single +sed patch to the font mapping path. diff --git a/debian/extra/fonts/SymbolsNerdFontMono-Regular.ttf b/debian/extra/fonts/SymbolsNerdFontMono-Regular.ttf new file mode 100644 index 0000000..3b5a184 Binary files /dev/null and b/debian/extra/fonts/SymbolsNerdFontMono-Regular.ttf differ diff --git a/debian/extra/libraries/font_symbols_nerdfont_mono_regular.lua b/debian/extra/libraries/font_symbols_nerdfont_mono_regular.lua new file mode 100644 index 0000000..16a0e26 --- /dev/null +++ b/debian/extra/libraries/font_symbols_nerdfont_mono_regular.lua @@ -0,0 +1,9372 @@ +-- To obtain the mapping: +--[[ +wget -qO - https://github.com/ryanoasis/nerd-fonts/raw/master/glyphnames.json \ +| jq -r 'with_entries(select(.key != "METADATA")) | keys_unsorted[] as $keys | "\($keys)\t\(.[$keys] | .code)"' \ +| awk ' + BEGIN { + printf "{\n" + } + { + printf " [\"%s\"] = 0x%s,\n", $1, $2 + } + END { + printf "}\n" + }' +--]] + +local codepoints = { + ["cod-account"] = 0xeb99, + ["cod-activate_breakpoints"] = 0xea97, + ["cod-add"] = 0xea60, + ["cod-archive"] = 0xea98, + ["cod-arrow_both"] = 0xea99, + ["cod-arrow_down"] = 0xea9a, + ["cod-arrow_left"] = 0xea9b, + ["cod-arrow_right"] = 0xea9c, + ["cod-arrow_small_down"] = 0xea9d, + ["cod-arrow_small_left"] = 0xea9e, + ["cod-arrow_small_right"] = 0xea9f, + ["cod-arrow_small_up"] = 0xeaa0, + ["cod-arrow_swap"] = 0xebcb, + ["cod-arrow_up"] = 0xeaa1, + ["cod-azure"] = 0xebd8, + ["cod-azure_devops"] = 0xebe8, + ["cod-beaker"] = 0xea79, + ["cod-beaker_stop"] = 0xebe1, + ["cod-bell"] = 0xeaa2, + ["cod-bell_dot"] = 0xeb9a, + ["cod-bold"] = 0xeaa3, + ["cod-book"] = 0xeaa4, + ["cod-bookmark"] = 0xeaa5, + ["cod-bracket_dot"] = 0xebe5, + ["cod-bracket_error"] = 0xebe6, + ["cod-briefcase"] = 0xeaac, + ["cod-broadcast"] = 0xeaad, + ["cod-browser"] = 0xeaae, + ["cod-bug"] = 0xeaaf, + ["cod-calendar"] = 0xeab0, + ["cod-call_incoming"] = 0xeb92, + ["cod-call_outgoing"] = 0xeb93, + ["cod-case_sensitive"] = 0xeab1, + ["cod-check"] = 0xeab2, + ["cod-check_all"] = 0xebb1, + ["cod-checklist"] = 0xeab3, + ["cod-chevron_down"] = 0xeab4, + ["cod-chevron_left"] = 0xeab5, + ["cod-chevron_right"] = 0xeab6, + ["cod-chevron_up"] = 0xeab7, + ["cod-chrome_close"] = 0xeab8, + ["cod-chrome_maximize"] = 0xeab9, + ["cod-chrome_minimize"] = 0xeaba, + ["cod-chrome_restore"] = 0xeabb, + ["cod-circle"] = 0xeabc, + ["cod-circle_filled"] = 0xea71, + ["cod-circle_large"] = 0xebb5, + ["cod-circle_large_filled"] = 0xebb4, + ["cod-circle_slash"] = 0xeabd, + ["cod-circle_small_filled"] = 0xeb8a, + ["cod-circuit_board"] = 0xeabe, + ["cod-clear_all"] = 0xeabf, + ["cod-clippy"] = 0xeac0, + ["cod-close"] = 0xea76, + ["cod-close_all"] = 0xeac1, + ["cod-cloud"] = 0xebaa, + ["cod-cloud_download"] = 0xeac2, + ["cod-cloud_upload"] = 0xeac3, + ["cod-code"] = 0xeac4, + ["cod-collapse_all"] = 0xeac5, + ["cod-color_mode"] = 0xeac6, + ["cod-combine"] = 0xebb6, + ["cod-comment"] = 0xea6b, + ["cod-comment_discussion"] = 0xeac7, + ["cod-compass"] = 0xebd5, + ["cod-compass_active"] = 0xebd7, + ["cod-compass_dot"] = 0xebd6, + ["cod-copy"] = 0xebcc, + ["cod-credit_card"] = 0xeac9, + ["cod-dash"] = 0xeacc, + ["cod-dashboard"] = 0xeacd, + ["cod-database"] = 0xeace, + ["cod-debug"] = 0xead8, + ["cod-debug_all"] = 0xebdc, + ["cod-debug_alt"] = 0xeb91, + ["cod-debug_alt_small"] = 0xeba8, + ["cod-debug_breakpoint_conditional"] = 0xeaa7, + ["cod-debug_breakpoint_conditional_unverified"] = 0xeaa6, + ["cod-debug_breakpoint_data"] = 0xeaa9, + ["cod-debug_breakpoint_data_unverified"] = 0xeaa8, + ["cod-debug_breakpoint_function"] = 0xeb88, + ["cod-debug_breakpoint_function_unverified"] = 0xeb87, + ["cod-debug_breakpoint_log"] = 0xeaab, + ["cod-debug_breakpoint_log_unverified"] = 0xeaaa, + ["cod-debug_breakpoint_unsupported"] = 0xeb8c, + ["cod-debug_console"] = 0xeb9b, + ["cod-debug_continue"] = 0xeacf, + ["cod-debug_continue_small"] = 0xebe0, + ["cod-debug_coverage"] = 0xebdd, + ["cod-debug_disconnect"] = 0xead0, + ["cod-debug_line_by_line"] = 0xebd0, + ["cod-debug_pause"] = 0xead1, + ["cod-debug_rerun"] = 0xebc0, + ["cod-debug_restart"] = 0xead2, + ["cod-debug_restart_frame"] = 0xeb90, + ["cod-debug_reverse_continue"] = 0xeb8e, + ["cod-debug_stackframe"] = 0xeb8b, + ["cod-debug_stackframe_active"] = 0xeb89, + ["cod-debug_start"] = 0xead3, + ["cod-debug_step_back"] = 0xeb8f, + ["cod-debug_step_into"] = 0xead4, + ["cod-debug_step_out"] = 0xead5, + ["cod-debug_step_over"] = 0xead6, + ["cod-debug_stop"] = 0xead7, + ["cod-desktop_download"] = 0xea78, + ["cod-device_camera"] = 0xeada, + ["cod-device_camera_video"] = 0xead9, + ["cod-device_mobile"] = 0xeadb, + ["cod-diff"] = 0xeae1, + ["cod-diff_added"] = 0xeadc, + ["cod-diff_ignored"] = 0xeadd, + ["cod-diff_modified"] = 0xeade, + ["cod-diff_removed"] = 0xeadf, + ["cod-diff_renamed"] = 0xeae0, + ["cod-discard"] = 0xeae2, + ["cod-edit"] = 0xea73, + ["cod-editor_layout"] = 0xeae3, + ["cod-ellipsis"] = 0xea7c, + ["cod-empty_window"] = 0xeae4, + ["cod-error"] = 0xea87, + ["cod-exclude"] = 0xeae5, + ["cod-expand_all"] = 0xeb95, + ["cod-export"] = 0xebac, + ["cod-extensions"] = 0xeae6, + ["cod-eye"] = 0xea70, + ["cod-eye_closed"] = 0xeae7, + ["cod-feedback"] = 0xeb96, + ["cod-file"] = 0xea7b, + ["cod-file_binary"] = 0xeae8, + ["cod-file_code"] = 0xeae9, + ["cod-file_media"] = 0xeaea, + ["cod-file_pdf"] = 0xeaeb, + ["cod-file_submodule"] = 0xeaec, + ["cod-file_symlink_directory"] = 0xeaed, + ["cod-file_symlink_file"] = 0xeaee, + ["cod-file_zip"] = 0xeaef, + ["cod-files"] = 0xeaf0, + ["cod-filter"] = 0xeaf1, + ["cod-filter_filled"] = 0xebce, + ["cod-flame"] = 0xeaf2, + ["cod-fold"] = 0xeaf5, + ["cod-fold_down"] = 0xeaf3, + ["cod-fold_up"] = 0xeaf4, + ["cod-folder"] = 0xea83, + ["cod-folder_active"] = 0xeaf6, + ["cod-folder_library"] = 0xebdf, + ["cod-folder_opened"] = 0xeaf7, + ["cod-gear"] = 0xeaf8, + ["cod-gift"] = 0xeaf9, + ["cod-gist_secret"] = 0xeafa, + ["cod-git_commit"] = 0xeafc, + ["cod-git_compare"] = 0xeafd, + ["cod-git_merge"] = 0xeafe, + ["cod-git_pull_request"] = 0xea64, + ["cod-git_pull_request_closed"] = 0xebda, + ["cod-git_pull_request_create"] = 0xebbc, + ["cod-git_pull_request_draft"] = 0xebdb, + ["cod-github"] = 0xea84, + ["cod-github_action"] = 0xeaff, + ["cod-github_alt"] = 0xeb00, + ["cod-github_inverted"] = 0xeba1, + ["cod-globe"] = 0xeb01, + ["cod-go_to_file"] = 0xea94, + ["cod-grabber"] = 0xeb02, + ["cod-graph"] = 0xeb03, + ["cod-graph_left"] = 0xebad, + ["cod-graph_line"] = 0xebe2, + ["cod-graph_scatter"] = 0xebe3, + ["cod-gripper"] = 0xeb04, + ["cod-group_by_ref_type"] = 0xeb97, + ["cod-heart"] = 0xeb05, + ["cod-history"] = 0xea82, + ["cod-home"] = 0xeb06, + ["cod-horizontal_rule"] = 0xeb07, + ["cod-hubot"] = 0xeb08, + ["cod-inbox"] = 0xeb09, + ["cod-info"] = 0xea74, + ["cod-inspect"] = 0xebd1, + ["cod-issue_draft"] = 0xebd9, + ["cod-issue_reopened"] = 0xeb0b, + ["cod-issues"] = 0xeb0c, + ["cod-italic"] = 0xeb0d, + ["cod-jersey"] = 0xeb0e, + ["cod-json"] = 0xeb0f, + ["cod-kebab_vertical"] = 0xeb10, + ["cod-key"] = 0xeb11, + ["cod-law"] = 0xeb12, + ["cod-layers"] = 0xebd2, + ["cod-layers_active"] = 0xebd4, + ["cod-layers_dot"] = 0xebd3, + ["cod-layout"] = 0xebeb, + ["cod-library"] = 0xeb9c, + ["cod-lightbulb"] = 0xea61, + ["cod-lightbulb_autofix"] = 0xeb13, + ["cod-link"] = 0xeb15, + ["cod-link_external"] = 0xeb14, + ["cod-list_filter"] = 0xeb83, + ["cod-list_flat"] = 0xeb84, + ["cod-list_ordered"] = 0xeb16, + ["cod-list_selection"] = 0xeb85, + ["cod-list_tree"] = 0xeb86, + ["cod-list_unordered"] = 0xeb17, + ["cod-live_share"] = 0xeb18, + ["cod-loading"] = 0xeb19, + ["cod-location"] = 0xeb1a, + ["cod-lock"] = 0xea75, + ["cod-lock_small"] = 0xebe7, + ["cod-magnet"] = 0xebae, + ["cod-mail"] = 0xeb1c, + ["cod-mail_read"] = 0xeb1b, + ["cod-markdown"] = 0xeb1d, + ["cod-megaphone"] = 0xeb1e, + ["cod-mention"] = 0xeb1f, + ["cod-menu"] = 0xeb94, + ["cod-merge"] = 0xebab, + ["cod-milestone"] = 0xeb20, + ["cod-mirror"] = 0xea69, + ["cod-mortar_board"] = 0xeb21, + ["cod-move"] = 0xeb22, + ["cod-multiple_windows"] = 0xeb23, + ["cod-mute"] = 0xeb24, + ["cod-new_file"] = 0xea7f, + ["cod-new_folder"] = 0xea80, + ["cod-newline"] = 0xebea, + ["cod-no_newline"] = 0xeb25, + ["cod-note"] = 0xeb26, + ["cod-notebook"] = 0xebaf, + ["cod-notebook_template"] = 0xebbf, + ["cod-octoface"] = 0xeb27, + ["cod-open_preview"] = 0xeb28, + ["cod-organization"] = 0xea7e, + ["cod-output"] = 0xeb9d, + ["cod-package"] = 0xeb29, + ["cod-paintcan"] = 0xeb2a, + ["cod-pass"] = 0xeba4, + ["cod-pass_filled"] = 0xebb3, + ["cod-person"] = 0xea67, + ["cod-person_add"] = 0xebcd, + ["cod-pie_chart"] = 0xebe4, + ["cod-pin"] = 0xeb2b, + ["cod-pinned"] = 0xeba0, + ["cod-pinned_dirty"] = 0xebb2, + ["cod-play"] = 0xeb2c, + ["cod-play_circle"] = 0xeba6, + ["cod-plug"] = 0xeb2d, + ["cod-preserve_case"] = 0xeb2e, + ["cod-preview"] = 0xeb2f, + ["cod-primitive_square"] = 0xea72, + ["cod-project"] = 0xeb30, + ["cod-pulse"] = 0xeb31, + ["cod-question"] = 0xeb32, + ["cod-quote"] = 0xeb33, + ["cod-radio_tower"] = 0xeb34, + ["cod-reactions"] = 0xeb35, + ["cod-record"] = 0xeba7, + ["cod-record_keys"] = 0xea65, + ["cod-redo"] = 0xebb0, + ["cod-references"] = 0xeb36, + ["cod-refresh"] = 0xeb37, + ["cod-regex"] = 0xeb38, + ["cod-remote"] = 0xeb3a, + ["cod-remote_explorer"] = 0xeb39, + ["cod-remove"] = 0xeb3b, + ["cod-replace"] = 0xeb3d, + ["cod-replace_all"] = 0xeb3c, + ["cod-reply"] = 0xea7d, + ["cod-repo"] = 0xea62, + ["cod-repo_clone"] = 0xeb3e, + ["cod-repo_force_push"] = 0xeb3f, + ["cod-repo_forked"] = 0xea63, + ["cod-repo_pull"] = 0xeb40, + ["cod-repo_push"] = 0xeb41, + ["cod-report"] = 0xeb42, + ["cod-request_changes"] = 0xeb43, + ["cod-rocket"] = 0xeb44, + ["cod-root_folder"] = 0xeb46, + ["cod-root_folder_opened"] = 0xeb45, + ["cod-rss"] = 0xeb47, + ["cod-ruby"] = 0xeb48, + ["cod-run_above"] = 0xebbd, + ["cod-run_all"] = 0xeb9e, + ["cod-run_below"] = 0xebbe, + ["cod-run_errors"] = 0xebde, + ["cod-save"] = 0xeb4b, + ["cod-save_all"] = 0xeb49, + ["cod-save_as"] = 0xeb4a, + ["cod-screen_full"] = 0xeb4c, + ["cod-screen_normal"] = 0xeb4d, + ["cod-search"] = 0xea6d, + ["cod-search_stop"] = 0xeb4e, + ["cod-server"] = 0xeb50, + ["cod-server_environment"] = 0xeba3, + ["cod-server_process"] = 0xeba2, + ["cod-settings"] = 0xeb52, + ["cod-settings_gear"] = 0xeb51, + ["cod-shield"] = 0xeb53, + ["cod-sign_in"] = 0xea6f, + ["cod-sign_out"] = 0xea6e, + ["cod-smiley"] = 0xeb54, + ["cod-sort_precedence"] = 0xeb55, + ["cod-source_control"] = 0xea68, + ["cod-split_horizontal"] = 0xeb56, + ["cod-split_vertical"] = 0xeb57, + ["cod-squirrel"] = 0xeb58, + ["cod-star_empty"] = 0xea6a, + ["cod-star_full"] = 0xeb59, + ["cod-star_half"] = 0xeb5a, + ["cod-stop_circle"] = 0xeba5, + ["cod-symbol_array"] = 0xea8a, + ["cod-symbol_boolean"] = 0xea8f, + ["cod-symbol_class"] = 0xeb5b, + ["cod-symbol_color"] = 0xeb5c, + ["cod-symbol_constant"] = 0xeb5d, + ["cod-symbol_enum"] = 0xea95, + ["cod-symbol_enum_member"] = 0xeb5e, + ["cod-symbol_event"] = 0xea86, + ["cod-symbol_field"] = 0xeb5f, + ["cod-symbol_file"] = 0xeb60, + ["cod-symbol_interface"] = 0xeb61, + ["cod-symbol_key"] = 0xea93, + ["cod-symbol_keyword"] = 0xeb62, + ["cod-symbol_method"] = 0xea8c, + ["cod-symbol_misc"] = 0xeb63, + ["cod-symbol_namespace"] = 0xea8b, + ["cod-symbol_numeric"] = 0xea90, + ["cod-symbol_operator"] = 0xeb64, + ["cod-symbol_parameter"] = 0xea92, + ["cod-symbol_property"] = 0xeb65, + ["cod-symbol_ruler"] = 0xea96, + ["cod-symbol_snippet"] = 0xeb66, + ["cod-symbol_string"] = 0xeb8d, + ["cod-symbol_structure"] = 0xea91, + ["cod-symbol_variable"] = 0xea88, + ["cod-sync"] = 0xea77, + ["cod-sync_ignored"] = 0xeb9f, + ["cod-table"] = 0xebb7, + ["cod-tag"] = 0xea66, + ["cod-tasklist"] = 0xeb67, + ["cod-telescope"] = 0xeb68, + ["cod-terminal"] = 0xea85, + ["cod-terminal_bash"] = 0xebca, + ["cod-terminal_cmd"] = 0xebc4, + ["cod-terminal_debian"] = 0xebc5, + ["cod-terminal_linux"] = 0xebc6, + ["cod-terminal_powershell"] = 0xebc7, + ["cod-terminal_tmux"] = 0xebc8, + ["cod-terminal_ubuntu"] = 0xebc9, + ["cod-text_size"] = 0xeb69, + ["cod-three_bars"] = 0xeb6a, + ["cod-thumbsdown"] = 0xeb6b, + ["cod-thumbsup"] = 0xeb6c, + ["cod-tools"] = 0xeb6d, + ["cod-trash"] = 0xea81, + ["cod-triangle_down"] = 0xeb6e, + ["cod-triangle_left"] = 0xeb6f, + ["cod-triangle_right"] = 0xeb70, + ["cod-triangle_up"] = 0xeb71, + ["cod-twitter"] = 0xeb72, + ["cod-type_hierarchy"] = 0xebb9, + ["cod-type_hierarchy_sub"] = 0xebba, + ["cod-type_hierarchy_super"] = 0xebbb, + ["cod-unfold"] = 0xeb73, + ["cod-ungroup_by_ref_type"] = 0xeb98, + ["cod-unlock"] = 0xeb74, + ["cod-unmute"] = 0xeb75, + ["cod-unverified"] = 0xeb76, + ["cod-variable_group"] = 0xebb8, + ["cod-verified"] = 0xeb77, + ["cod-verified_filled"] = 0xebe9, + ["cod-versions"] = 0xeb78, + ["cod-vm"] = 0xea7a, + ["cod-vm_active"] = 0xeb79, + ["cod-vm_connect"] = 0xeba9, + ["cod-vm_outline"] = 0xeb7a, + ["cod-vm_running"] = 0xeb7b, + ["cod-wand"] = 0xebcf, + ["cod-warning"] = 0xea6c, + ["cod-watch"] = 0xeb7c, + ["cod-whitespace"] = 0xeb7d, + ["cod-whole_word"] = 0xeb7e, + ["cod-window"] = 0xeb7f, + ["cod-word_wrap"] = 0xeb80, + ["cod-workspace_trusted"] = 0xebc1, + ["cod-workspace_unknown"] = 0xebc3, + ["cod-workspace_untrusted"] = 0xebc2, + ["cod-zoom_in"] = 0xeb81, + ["cod-zoom_out"] = 0xeb82, + ["custom-asm"] = 0xe6ab, + ["custom-c"] = 0xe61e, + ["custom-common_lisp"] = 0xe6b0, + ["custom-cpp"] = 0xe61d, + ["custom-crystal"] = 0xe62f, + ["custom-default"] = 0xe612, + ["custom-electron"] = 0xe62e, + ["custom-elixir"] = 0xe62d, + ["custom-elm"] = 0xe62c, + ["custom-emacs"] = 0xe632, + ["custom-fennel"] = 0xe6af, + ["custom-folder"] = 0xe5ff, + ["custom-folder_config"] = 0xe5fc, + ["custom-folder_git"] = 0xe5fb, + ["custom-folder_git_branch"] = 0xe5fb, + ["custom-folder_github"] = 0xe5fd, + ["custom-folder_npm"] = 0xe5fa, + ["custom-folder_oct"] = 0xe6ad, + ["custom-folder_open"] = 0xe5fe, + ["custom-go"] = 0xe626, + ["custom-home"] = 0xe617, + ["custom-kotlin"] = 0xe634, + ["custom-msdos"] = 0xe629, + ["custom-neovim"] = 0xe6ae, + ["custom-orgmode"] = 0xe633, + ["custom-play_arrow"] = 0xe602, + ["custom-puppet"] = 0xe631, + ["custom-purescript"] = 0xe630, + ["custom-scheme"] = 0xe6b1, + ["custom-toml"] = 0xe6b2, + ["custom-v_lang"] = 0xe6ac, + ["custom-vim"] = 0xe62b, + ["custom-windows"] = 0xe62a, + ["dev-android"] = 0xe70e, + ["dev-angular"] = 0xe753, + ["dev-appcelerator"] = 0xe7ab, + ["dev-apple"] = 0xe711, + ["dev-appstore"] = 0xe713, + ["dev-aptana"] = 0xe799, + ["dev-asterisk"] = 0xe7ac, + ["dev-atlassian"] = 0xe75b, + ["dev-atom"] = 0xe764, + ["dev-aws"] = 0xe7ad, + ["dev-backbone"] = 0xe752, + ["dev-bing_small"] = 0xe700, + ["dev-bintray"] = 0xe794, + ["dev-bitbucket"] = 0xe703, + ["dev-blackberry"] = 0xe723, + ["dev-bootstrap"] = 0xe747, + ["dev-bower"] = 0xe74d, + ["dev-brackets"] = 0xe79d, + ["dev-bugsense"] = 0xe78d, + ["dev-celluloid"] = 0xe76b, + ["dev-chart"] = 0xe760, + ["dev-chrome"] = 0xe743, + ["dev-cisco"] = 0xe765, + ["dev-clojure"] = 0xe768, + ["dev-clojure_alt"] = 0xe76a, + ["dev-cloud9"] = 0xe79f, + ["dev-coda"] = 0xe793, + ["dev-code"] = 0xe796, + ["dev-code_badge"] = 0xe7a3, + ["dev-codeigniter"] = 0xe780, + ["dev-codepen"] = 0xe716, + ["dev-codrops"] = 0xe72f, + ["dev-coffeescript"] = 0xe751, + ["dev-compass"] = 0xe761, + ["dev-composer"] = 0xe783, + ["dev-creativecommons"] = 0xe789, + ["dev-creativecommons_badge"] = 0xe78a, + ["dev-css3"] = 0xe749, + ["dev-css3_full"] = 0xe74a, + ["dev-css_tricks"] = 0xe701, + ["dev-cssdeck"] = 0xe72a, + ["dev-dart"] = 0xe798, + ["dev-database"] = 0xe706, + ["dev-debian"] = 0xe77d, + ["dev-digital_ocean"] = 0xe7ae, + ["dev-django"] = 0xe71d, + ["dev-dlang"] = 0xe7af, + ["dev-docker"] = 0xe7b0, + ["dev-doctrine"] = 0xe774, + ["dev-dojo"] = 0xe71c, + ["dev-dotnet"] = 0xe77f, + ["dev-dreamweaver"] = 0xe79c, + ["dev-dropbox"] = 0xe707, + ["dev-drupal"] = 0xe742, + ["dev-eclipse"] = 0xe79e, + ["dev-ember"] = 0xe71b, + ["dev-envato"] = 0xe75d, + ["dev-erlang"] = 0xe7b1, + ["dev-extjs"] = 0xe78e, + ["dev-firebase"] = 0xe787, + ["dev-firefox"] = 0xe745, + ["dev-fsharp"] = 0xe7a7, + ["dev-ghost"] = 0xe71f, + ["dev-ghost_small"] = 0xe714, + ["dev-git"] = 0xe702, + ["dev-git_branch"] = 0xe725, + ["dev-git_commit"] = 0xe729, + ["dev-git_compare"] = 0xe728, + ["dev-git_merge"] = 0xe727, + ["dev-git_pull_request"] = 0xe726, + ["dev-github"] = 0xe70a, + ["dev-github_alt"] = 0xe708, + ["dev-github_badge"] = 0xe709, + ["dev-github_full"] = 0xe717, + ["dev-gnu"] = 0xe779, + ["dev-go"] = 0xe724, + ["dev-google_cloud_platform"] = 0xe7b2, + ["dev-google_drive"] = 0xe731, + ["dev-grails"] = 0xe7b3, + ["dev-groovy"] = 0xe775, + ["dev-grunt"] = 0xe74c, + ["dev-gulp"] = 0xe763, + ["dev-hackernews"] = 0xe71a, + ["dev-haskell"] = 0xe777, + ["dev-heroku"] = 0xe77b, + ["dev-html5"] = 0xe736, + ["dev-html5_3d_effects"] = 0xe735, + ["dev-html5_connectivity"] = 0xe734, + ["dev-html5_device_access"] = 0xe733, + ["dev-html5_multimedia"] = 0xe732, + ["dev-ie"] = 0xe744, + ["dev-illustrator"] = 0xe7b4, + ["dev-intellij"] = 0xe7b5, + ["dev-ionic"] = 0xe7a9, + ["dev-java"] = 0xe738, + ["dev-javascript"] = 0xe74e, + ["dev-javascript_badge"] = 0xe781, + ["dev-javascript_shield"] = 0xe74f, + ["dev-jekyll_small"] = 0xe70d, + ["dev-jenkins"] = 0xe767, + ["dev-jira"] = 0xe75c, + ["dev-joomla"] = 0xe741, + ["dev-jquery"] = 0xe750, + ["dev-jquery_ui"] = 0xe754, + ["dev-komodo"] = 0xe792, + ["dev-krakenjs"] = 0xe785, + ["dev-krakenjs_badge"] = 0xe784, + ["dev-laravel"] = 0xe73f, + ["dev-less"] = 0xe758, + ["dev-linux"] = 0xe712, + ["dev-magento"] = 0xe740, + ["dev-mailchimp"] = 0xe79a, + ["dev-markdown"] = 0xe73e, + ["dev-materializecss"] = 0xe7b6, + ["dev-meteor"] = 0xe7a5, + ["dev-meteorfull"] = 0xe7a6, + ["dev-mitlicence"] = 0xe78b, + ["dev-modernizr"] = 0xe720, + ["dev-mongodb"] = 0xe7a4, + ["dev-mootools"] = 0xe790, + ["dev-mootools_badge"] = 0xe78f, + ["dev-mozilla"] = 0xe786, + ["dev-msql_server"] = 0xe77c, + ["dev-mysql"] = 0xe704, + ["dev-nancy"] = 0xe766, + ["dev-netbeans"] = 0xe79b, + ["dev-netmagazine"] = 0xe72e, + ["dev-nginx"] = 0xe776, + ["dev-nodejs"] = 0xe719, + ["dev-nodejs_small"] = 0xe718, + ["dev-npm"] = 0xe71e, + ["dev-onedrive"] = 0xe762, + ["dev-openshift"] = 0xe7b7, + ["dev-opensource"] = 0xe771, + ["dev-opera"] = 0xe746, + ["dev-perl"] = 0xe769, + ["dev-phonegap"] = 0xe730, + ["dev-photoshop"] = 0xe7b8, + ["dev-php"] = 0xe73d, + ["dev-postgresql"] = 0xe76e, + ["dev-prolog"] = 0xe7a1, + ["dev-python"] = 0xe73c, + ["dev-rackspace"] = 0xe7b9, + ["dev-raphael"] = 0xe75f, + ["dev-rasberry_pi"] = 0xe722, + ["dev-react"] = 0xe7ba, + ["dev-redhat"] = 0xe7bb, + ["dev-redis"] = 0xe76d, + ["dev-requirejs"] = 0xe770, + ["dev-responsive"] = 0xe797, + ["dev-ruby"] = 0xe739, + ["dev-ruby_on_rails"] = 0xe73b, + ["dev-ruby_rough"] = 0xe791, + ["dev-rust"] = 0xe7a8, + ["dev-safari"] = 0xe748, + ["dev-sass"] = 0xe74b, + ["dev-scala"] = 0xe737, + ["dev-scriptcs"] = 0xe7bc, + ["dev-scrum"] = 0xe7a0, + ["dev-senchatouch"] = 0xe78c, + ["dev-sizzlejs"] = 0xe788, + ["dev-smashing_magazine"] = 0xe72d, + ["dev-snap_svg"] = 0xe75e, + ["dev-sqllite"] = 0xe7c4, + ["dev-stackoverflow"] = 0xe710, + ["dev-streamline"] = 0xe705, + ["dev-stylus"] = 0xe759, + ["dev-sublime"] = 0xe7aa, + ["dev-swift"] = 0xe755, + ["dev-symfony"] = 0xe756, + ["dev-symfony_badge"] = 0xe757, + ["dev-techcrunch"] = 0xe72c, + ["dev-terminal"] = 0xe795, + ["dev-terminal_badge"] = 0xe7a2, + ["dev-travis"] = 0xe77e, + ["dev-trello"] = 0xe75a, + ["dev-typo3"] = 0xe772, + ["dev-ubuntu"] = 0xe73a, + ["dev-uikit"] = 0xe773, + ["dev-unity_small"] = 0xe721, + ["dev-vim"] = 0xe7c5, + ["dev-visualstudio"] = 0xe70c, + ["dev-w3c"] = 0xe76c, + ["dev-webplatform"] = 0xe76f, + ["dev-windows"] = 0xe70f, + ["dev-wordpress"] = 0xe70b, + ["dev-yahoo"] = 0xe715, + ["dev-yahoo_small"] = 0xe72b, + ["dev-yeoman"] = 0xe77a, + ["dev-yii"] = 0xe782, + ["dev-zend"] = 0xe778, + ["fa-500px"] = 0xf26e, + ["fa-address_book"] = 0xf2b9, + ["fa-address_book_o"] = 0xf2ba, + ["fa-address_card"] = 0xf2bb, + ["fa-address_card_o"] = 0xf2bc, + ["fa-adjust"] = 0xf042, + ["fa-adn"] = 0xf170, + ["fa-align_center"] = 0xf037, + ["fa-align_justify"] = 0xf039, + ["fa-align_left"] = 0xf036, + ["fa-align_right"] = 0xf038, + ["fa-amazon"] = 0xf270, + ["fa-ambulance"] = 0xf0f9, + ["fa-american_sign_language_interpreting"] = 0xf2a3, + ["fa-anchor"] = 0xf13d, + ["fa-android"] = 0xf17b, + ["fa-angellist"] = 0xf209, + ["fa-angle_double_down"] = 0xf103, + ["fa-angle_double_left"] = 0xf100, + ["fa-angle_double_right"] = 0xf101, + ["fa-angle_double_up"] = 0xf102, + ["fa-angle_down"] = 0xf107, + ["fa-angle_left"] = 0xf104, + ["fa-angle_right"] = 0xf105, + ["fa-angle_up"] = 0xf106, + ["fa-apple"] = 0xf179, + ["fa-archive"] = 0xf187, + ["fa-area_chart"] = 0xf1fe, + ["fa-arrow_circle_down"] = 0xf0ab, + ["fa-arrow_circle_left"] = 0xf0a8, + ["fa-arrow_circle_o_down"] = 0xf01a, + ["fa-arrow_circle_o_left"] = 0xf190, + ["fa-arrow_circle_o_right"] = 0xf18e, + ["fa-arrow_circle_o_up"] = 0xf01b, + ["fa-arrow_circle_right"] = 0xf0a9, + ["fa-arrow_circle_up"] = 0xf0aa, + ["fa-arrow_down"] = 0xf063, + ["fa-arrow_left"] = 0xf060, + ["fa-arrow_right"] = 0xf061, + ["fa-arrow_up"] = 0xf062, + ["fa-arrows"] = 0xf047, + ["fa-arrows_alt"] = 0xf0b2, + ["fa-arrows_h"] = 0xf07e, + ["fa-arrows_v"] = 0xf07d, + ["fa-asl_interpreting"] = 0xf2a3, + ["fa-assistive_listening_systems"] = 0xf2a2, + ["fa-asterisk"] = 0xf069, + ["fa-at"] = 0xf1fa, + ["fa-audio_description"] = 0xf29e, + ["fa-automobile"] = 0xf1b9, + ["fa-backward"] = 0xf04a, + ["fa-balance_scale"] = 0xf24e, + ["fa-ban"] = 0xf05e, + ["fa-bandcamp"] = 0xf2d5, + ["fa-bank"] = 0xf19c, + ["fa-bar_chart"] = 0xf080, + ["fa-bar_chart_o"] = 0xf080, + ["fa-barcode"] = 0xf02a, + ["fa-bars"] = 0xf0c9, + ["fa-bath"] = 0xf2cd, + ["fa-bathtub"] = 0xf2cd, + ["fa-battery"] = 0xf240, + ["fa-battery_0"] = 0xf244, + ["fa-battery_1"] = 0xf243, + ["fa-battery_2"] = 0xf242, + ["fa-battery_3"] = 0xf241, + ["fa-battery_4"] = 0xf240, + ["fa-battery_empty"] = 0xf244, + ["fa-battery_full"] = 0xf240, + ["fa-battery_half"] = 0xf242, + ["fa-battery_quarter"] = 0xf243, + ["fa-battery_three_quarters"] = 0xf241, + ["fa-bed"] = 0xf236, + ["fa-beer"] = 0xf0fc, + ["fa-behance"] = 0xf1b4, + ["fa-behance_square"] = 0xf1b5, + ["fa-bell"] = 0xf0f3, + ["fa-bell_o"] = 0xf0a2, + ["fa-bell_slash"] = 0xf1f6, + ["fa-bell_slash_o"] = 0xf1f7, + ["fa-bicycle"] = 0xf206, + ["fa-binoculars"] = 0xf1e5, + ["fa-birthday_cake"] = 0xf1fd, + ["fa-bitbucket"] = 0xf171, + ["fa-bitbucket_square"] = 0xf172, + ["fa-bitcoin"] = 0xf15a, + ["fa-black_tie"] = 0xf27e, + ["fa-blind"] = 0xf29d, + ["fa-bluetooth"] = 0xf293, + ["fa-bluetooth_b"] = 0xf294, + ["fa-bold"] = 0xf032, + ["fa-bolt"] = 0xf0e7, + ["fa-bomb"] = 0xf1e2, + ["fa-book"] = 0xf02d, + ["fa-bookmark"] = 0xf02e, + ["fa-bookmark_o"] = 0xf097, + ["fa-braille"] = 0xf2a1, + ["fa-briefcase"] = 0xf0b1, + ["fa-btc"] = 0xf15a, + ["fa-bug"] = 0xf188, + ["fa-building"] = 0xf1ad, + ["fa-building_o"] = 0xf0f7, + ["fa-bullhorn"] = 0xf0a1, + ["fa-bullseye"] = 0xf140, + ["fa-bus"] = 0xf207, + ["fa-buysellads"] = 0xf20d, + ["fa-cab"] = 0xf1ba, + ["fa-calculator"] = 0xf1ec, + ["fa-calendar"] = 0xf073, + ["fa-calendar_check_o"] = 0xf274, + ["fa-calendar_minus_o"] = 0xf272, + ["fa-calendar_o"] = 0xf133, + ["fa-calendar_plus_o"] = 0xf271, + ["fa-calendar_times_o"] = 0xf273, + ["fa-camera"] = 0xf030, + ["fa-camera_retro"] = 0xf083, + ["fa-car"] = 0xf1b9, + ["fa-caret_down"] = 0xf0d7, + ["fa-caret_left"] = 0xf0d9, + ["fa-caret_right"] = 0xf0da, + ["fa-caret_square_o_down"] = 0xf150, + ["fa-caret_square_o_left"] = 0xf191, + ["fa-caret_square_o_right"] = 0xf152, + ["fa-caret_square_o_up"] = 0xf151, + ["fa-caret_up"] = 0xf0d8, + ["fa-cart_arrow_down"] = 0xf218, + ["fa-cart_plus"] = 0xf217, + ["fa-cc"] = 0xf20a, + ["fa-cc_amex"] = 0xf1f3, + ["fa-cc_diners_club"] = 0xf24c, + ["fa-cc_discover"] = 0xf1f2, + ["fa-cc_jcb"] = 0xf24b, + ["fa-cc_mastercard"] = 0xf1f1, + ["fa-cc_paypal"] = 0xf1f4, + ["fa-cc_stripe"] = 0xf1f5, + ["fa-cc_visa"] = 0xf1f0, + ["fa-certificate"] = 0xf0a3, + ["fa-chain"] = 0xf0c1, + ["fa-chain_broken"] = 0xf127, + ["fa-check"] = 0xf00c, + ["fa-check_circle"] = 0xf058, + ["fa-check_circle_o"] = 0xf05d, + ["fa-check_square"] = 0xf14a, + ["fa-check_square_o"] = 0xf046, + ["fa-chevron_circle_down"] = 0xf13a, + ["fa-chevron_circle_left"] = 0xf137, + ["fa-chevron_circle_right"] = 0xf138, + ["fa-chevron_circle_up"] = 0xf139, + ["fa-chevron_down"] = 0xf078, + ["fa-chevron_left"] = 0xf053, + ["fa-chevron_right"] = 0xf054, + ["fa-chevron_up"] = 0xf077, + ["fa-child"] = 0xf1ae, + ["fa-chrome"] = 0xf268, + ["fa-circle"] = 0xf111, + ["fa-circle_o"] = 0xf10c, + ["fa-circle_o_notch"] = 0xf1ce, + ["fa-circle_thin"] = 0xf1db, + ["fa-clipboard"] = 0xf0ea, + ["fa-clock_o"] = 0xf017, + ["fa-clone"] = 0xf24d, + ["fa-close"] = 0xf00d, + ["fa-cloud"] = 0xf0c2, + ["fa-cloud_download"] = 0xf0ed, + ["fa-cloud_upload"] = 0xf0ee, + ["fa-cny"] = 0xf157, + ["fa-code"] = 0xf121, + ["fa-code_fork"] = 0xf126, + ["fa-codepen"] = 0xf1cb, + ["fa-codiepie"] = 0xf284, + ["fa-coffee"] = 0xf0f4, + ["fa-cog"] = 0xf013, + ["fa-cogs"] = 0xf085, + ["fa-columns"] = 0xf0db, + ["fa-comment"] = 0xf075, + ["fa-comment_o"] = 0xf0e5, + ["fa-commenting"] = 0xf27a, + ["fa-commenting_o"] = 0xf27b, + ["fa-comments"] = 0xf086, + ["fa-comments_o"] = 0xf0e6, + ["fa-compass"] = 0xf14e, + ["fa-compress"] = 0xf066, + ["fa-connectdevelop"] = 0xf20e, + ["fa-contao"] = 0xf26d, + ["fa-copy"] = 0xf0c5, + ["fa-copyright"] = 0xf1f9, + ["fa-creative_commons"] = 0xf25e, + ["fa-credit_card"] = 0xf09d, + ["fa-credit_card_alt"] = 0xf283, + ["fa-crop"] = 0xf125, + ["fa-crosshairs"] = 0xf05b, + ["fa-css3"] = 0xf13c, + ["fa-cube"] = 0xf1b2, + ["fa-cubes"] = 0xf1b3, + ["fa-cut"] = 0xf0c4, + ["fa-cutlery"] = 0xf0f5, + ["fa-dashboard"] = 0xf0e4, + ["fa-dashcube"] = 0xf210, + ["fa-database"] = 0xf1c0, + ["fa-deaf"] = 0xf2a4, + ["fa-deafness"] = 0xf2a4, + ["fa-dedent"] = 0xf03b, + ["fa-delicious"] = 0xf1a5, + ["fa-desktop"] = 0xf108, + ["fa-deviantart"] = 0xf1bd, + ["fa-diamond"] = 0xf219, + ["fa-digg"] = 0xf1a6, + ["fa-dollar"] = 0xf155, + ["fa-dot_circle_o"] = 0xf192, + ["fa-download"] = 0xf019, + ["fa-dribbble"] = 0xf17d, + ["fa-drivers_license"] = 0xf2c2, + ["fa-drivers_license_o"] = 0xf2c3, + ["fa-dropbox"] = 0xf16b, + ["fa-drupal"] = 0xf1a9, + ["fa-edge"] = 0xf282, + ["fa-edit"] = 0xf044, + ["fa-eercast"] = 0xf2da, + ["fa-eject"] = 0xf052, + ["fa-ellipsis_h"] = 0xf141, + ["fa-ellipsis_v"] = 0xf142, + ["fa-empire"] = 0xf1d1, + ["fa-envelope"] = 0xf0e0, + ["fa-envelope_o"] = 0xf003, + ["fa-envelope_open"] = 0xf2b6, + ["fa-envelope_open_o"] = 0xf2b7, + ["fa-envelope_square"] = 0xf199, + ["fa-envira"] = 0xf299, + ["fa-eraser"] = 0xf12d, + ["fa-etsy"] = 0xf2d7, + ["fa-eur"] = 0xf153, + ["fa-euro"] = 0xf153, + ["fa-exchange"] = 0xf0ec, + ["fa-exclamation"] = 0xf12a, + ["fa-exclamation_circle"] = 0xf06a, + ["fa-exclamation_triangle"] = 0xf071, + ["fa-expand"] = 0xf065, + ["fa-expeditedssl"] = 0xf23e, + ["fa-external_link"] = 0xf08e, + ["fa-external_link_square"] = 0xf14c, + ["fa-eye"] = 0xf06e, + ["fa-eye_slash"] = 0xf070, + ["fa-eyedropper"] = 0xf1fb, + ["fa-fa"] = 0xf2b4, + ["fa-facebook"] = 0xf09a, + ["fa-facebook_f"] = 0xf09a, + ["fa-facebook_official"] = 0xf230, + ["fa-facebook_square"] = 0xf082, + ["fa-fast_backward"] = 0xf049, + ["fa-fast_forward"] = 0xf050, + ["fa-fax"] = 0xf1ac, + ["fa-feed"] = 0xf09e, + ["fa-female"] = 0xf182, + ["fa-fighter_jet"] = 0xf0fb, + ["fa-file"] = 0xf15b, + ["fa-file_archive_o"] = 0xf1c6, + ["fa-file_audio_o"] = 0xf1c7, + ["fa-file_code_o"] = 0xf1c9, + ["fa-file_excel_o"] = 0xf1c3, + ["fa-file_image_o"] = 0xf1c5, + ["fa-file_movie_o"] = 0xf1c8, + ["fa-file_o"] = 0xf016, + ["fa-file_pdf_o"] = 0xf1c1, + ["fa-file_photo_o"] = 0xf1c5, + ["fa-file_picture_o"] = 0xf1c5, + ["fa-file_powerpoint_o"] = 0xf1c4, + ["fa-file_sound_o"] = 0xf1c7, + ["fa-file_text"] = 0xf15c, + ["fa-file_text_o"] = 0xf0f6, + ["fa-file_video_o"] = 0xf1c8, + ["fa-file_word_o"] = 0xf1c2, + ["fa-file_zip_o"] = 0xf1c6, + ["fa-files_o"] = 0xf0c5, + ["fa-film"] = 0xf008, + ["fa-filter"] = 0xf0b0, + ["fa-fire"] = 0xf06d, + ["fa-fire_extinguisher"] = 0xf134, + ["fa-firefox"] = 0xf269, + ["fa-first_order"] = 0xf2b0, + ["fa-flag"] = 0xf024, + ["fa-flag_checkered"] = 0xf11e, + ["fa-flag_o"] = 0xf11d, + ["fa-flash"] = 0xf0e7, + ["fa-flask"] = 0xf0c3, + ["fa-flickr"] = 0xf16e, + ["fa-floppy_o"] = 0xf0c7, + ["fa-folder"] = 0xf07b, + ["fa-folder_o"] = 0xf114, + ["fa-folder_open"] = 0xf07c, + ["fa-folder_open_o"] = 0xf115, + ["fa-font"] = 0xf031, + ["fa-font_awesome"] = 0xf2b4, + ["fa-fonticons"] = 0xf280, + ["fa-fort_awesome"] = 0xf286, + ["fa-forumbee"] = 0xf211, + ["fa-forward"] = 0xf04e, + ["fa-foursquare"] = 0xf180, + ["fa-free_code_camp"] = 0xf2c5, + ["fa-frown_o"] = 0xf119, + ["fa-futbol_o"] = 0xf1e3, + ["fa-gamepad"] = 0xf11b, + ["fa-gavel"] = 0xf0e3, + ["fa-gbp"] = 0xf154, + ["fa-ge"] = 0xf1d1, + ["fa-gear"] = 0xf013, + ["fa-gears"] = 0xf085, + ["fa-genderless"] = 0xf22d, + ["fa-get_pocket"] = 0xf265, + ["fa-gg"] = 0xf260, + ["fa-gg_circle"] = 0xf261, + ["fa-gift"] = 0xf06b, + ["fa-git"] = 0xf1d3, + ["fa-git_square"] = 0xf1d2, + ["fa-github"] = 0xf09b, + ["fa-github_alt"] = 0xf113, + ["fa-github_square"] = 0xf092, + ["fa-gitlab"] = 0xf296, + ["fa-gittip"] = 0xf184, + ["fa-glass"] = 0xf000, + ["fa-glide"] = 0xf2a5, + ["fa-glide_g"] = 0xf2a6, + ["fa-globe"] = 0xf0ac, + ["fa-google"] = 0xf1a0, + ["fa-google_plus"] = 0xf0d5, + ["fa-google_plus_circle"] = 0xf2b3, + ["fa-google_plus_official"] = 0xf2b3, + ["fa-google_plus_square"] = 0xf0d4, + ["fa-google_wallet"] = 0xf1ee, + ["fa-graduation_cap"] = 0xf19d, + ["fa-gratipay"] = 0xf184, + ["fa-grav"] = 0xf2d6, + ["fa-group"] = 0xf0c0, + ["fa-h_square"] = 0xf0fd, + ["fa-hacker_news"] = 0xf1d4, + ["fa-hand_grab_o"] = 0xf255, + ["fa-hand_lizard_o"] = 0xf258, + ["fa-hand_o_down"] = 0xf0a7, + ["fa-hand_o_left"] = 0xf0a5, + ["fa-hand_o_right"] = 0xf0a4, + ["fa-hand_o_up"] = 0xf0a6, + ["fa-hand_paper_o"] = 0xf256, + ["fa-hand_peace_o"] = 0xf25b, + ["fa-hand_pointer_o"] = 0xf25a, + ["fa-hand_rock_o"] = 0xf255, + ["fa-hand_scissors_o"] = 0xf257, + ["fa-hand_spock_o"] = 0xf259, + ["fa-hand_stop_o"] = 0xf256, + ["fa-handshake_o"] = 0xf2b5, + ["fa-hard_of_hearing"] = 0xf2a4, + ["fa-hashtag"] = 0xf292, + ["fa-hdd_o"] = 0xf0a0, + ["fa-header"] = 0xf1dc, + ["fa-headphones"] = 0xf025, + ["fa-heart"] = 0xf004, + ["fa-heart_o"] = 0xf08a, + ["fa-heartbeat"] = 0xf21e, + ["fa-history"] = 0xf1da, + ["fa-home"] = 0xf015, + ["fa-hospital_o"] = 0xf0f8, + ["fa-hotel"] = 0xf236, + ["fa-hourglass"] = 0xf254, + ["fa-hourglass_1"] = 0xf251, + ["fa-hourglass_2"] = 0xf252, + ["fa-hourglass_3"] = 0xf253, + ["fa-hourglass_end"] = 0xf253, + ["fa-hourglass_half"] = 0xf252, + ["fa-hourglass_o"] = 0xf250, + ["fa-hourglass_start"] = 0xf251, + ["fa-houzz"] = 0xf27c, + ["fa-html5"] = 0xf13b, + ["fa-i_cursor"] = 0xf246, + ["fa-id_badge"] = 0xf2c1, + ["fa-id_card"] = 0xf2c2, + ["fa-id_card_o"] = 0xf2c3, + ["fa-ils"] = 0xf20b, + ["fa-image"] = 0xf03e, + ["fa-imdb"] = 0xf2d8, + ["fa-inbox"] = 0xf01c, + ["fa-indent"] = 0xf03c, + ["fa-industry"] = 0xf275, + ["fa-info"] = 0xf129, + ["fa-info_circle"] = 0xf05a, + ["fa-inr"] = 0xf156, + ["fa-instagram"] = 0xf16d, + ["fa-institution"] = 0xf19c, + ["fa-internet_explorer"] = 0xf26b, + ["fa-intersex"] = 0xf224, + ["fa-ioxhost"] = 0xf208, + ["fa-italic"] = 0xf033, + ["fa-joomla"] = 0xf1aa, + ["fa-jpy"] = 0xf157, + ["fa-jsfiddle"] = 0xf1cc, + ["fa-key"] = 0xf084, + ["fa-keyboard_o"] = 0xf11c, + ["fa-krw"] = 0xf159, + ["fa-language"] = 0xf1ab, + ["fa-laptop"] = 0xf109, + ["fa-lastfm"] = 0xf202, + ["fa-lastfm_square"] = 0xf203, + ["fa-leaf"] = 0xf06c, + ["fa-leanpub"] = 0xf212, + ["fa-legal"] = 0xf0e3, + ["fa-lemon_o"] = 0xf094, + ["fa-level_down"] = 0xf149, + ["fa-level_up"] = 0xf148, + ["fa-life_bouy"] = 0xf1cd, + ["fa-life_buoy"] = 0xf1cd, + ["fa-life_ring"] = 0xf1cd, + ["fa-life_saver"] = 0xf1cd, + ["fa-lightbulb_o"] = 0xf0eb, + ["fa-line_chart"] = 0xf201, + ["fa-link"] = 0xf0c1, + ["fa-linkedin"] = 0xf0e1, + ["fa-linkedin_square"] = 0xf08c, + ["fa-linode"] = 0xf2b8, + ["fa-linux"] = 0xf17c, + ["fa-list"] = 0xf03a, + ["fa-list_alt"] = 0xf022, + ["fa-list_ol"] = 0xf0cb, + ["fa-list_ul"] = 0xf0ca, + ["fa-location_arrow"] = 0xf124, + ["fa-lock"] = 0xf023, + ["fa-long_arrow_down"] = 0xf175, + ["fa-long_arrow_left"] = 0xf177, + ["fa-long_arrow_right"] = 0xf178, + ["fa-long_arrow_up"] = 0xf176, + ["fa-low_vision"] = 0xf2a8, + ["fa-magic"] = 0xf0d0, + ["fa-magnet"] = 0xf076, + ["fa-mail_forward"] = 0xf064, + ["fa-mail_reply"] = 0xf112, + ["fa-mail_reply_all"] = 0xf122, + ["fa-male"] = 0xf183, + ["fa-map"] = 0xf279, + ["fa-map_marker"] = 0xf041, + ["fa-map_o"] = 0xf278, + ["fa-map_pin"] = 0xf276, + ["fa-map_signs"] = 0xf277, + ["fa-mars"] = 0xf222, + ["fa-mars_double"] = 0xf227, + ["fa-mars_stroke"] = 0xf229, + ["fa-mars_stroke_h"] = 0xf22b, + ["fa-mars_stroke_v"] = 0xf22a, + ["fa-maxcdn"] = 0xf136, + ["fa-meanpath"] = 0xf20c, + ["fa-medium"] = 0xf23a, + ["fa-medkit"] = 0xf0fa, + ["fa-meetup"] = 0xf2e0, + ["fa-meh_o"] = 0xf11a, + ["fa-mercury"] = 0xf223, + ["fa-microchip"] = 0xf2db, + ["fa-microphone"] = 0xf130, + ["fa-microphone_slash"] = 0xf131, + ["fa-minus"] = 0xf068, + ["fa-minus_circle"] = 0xf056, + ["fa-minus_square"] = 0xf146, + ["fa-minus_square_o"] = 0xf147, + ["fa-mixcloud"] = 0xf289, + ["fa-mobile"] = 0xf10b, + ["fa-mobile_phone"] = 0xf10b, + ["fa-modx"] = 0xf285, + ["fa-money"] = 0xf0d6, + ["fa-moon_o"] = 0xf186, + ["fa-mortar_board"] = 0xf19d, + ["fa-motorcycle"] = 0xf21c, + ["fa-mouse_pointer"] = 0xf245, + ["fa-music"] = 0xf001, + ["fa-navicon"] = 0xf0c9, + ["fa-neuter"] = 0xf22c, + ["fa-newspaper_o"] = 0xf1ea, + ["fa-object_group"] = 0xf247, + ["fa-object_ungroup"] = 0xf248, + ["fa-odnoklassniki"] = 0xf263, + ["fa-odnoklassniki_square"] = 0xf264, + ["fa-opencart"] = 0xf23d, + ["fa-openid"] = 0xf19b, + ["fa-opera"] = 0xf26a, + ["fa-optin_monster"] = 0xf23c, + ["fa-outdent"] = 0xf03b, + ["fa-pagelines"] = 0xf18c, + ["fa-paint_brush"] = 0xf1fc, + ["fa-paper_plane"] = 0xf1d8, + ["fa-paper_plane_o"] = 0xf1d9, + ["fa-paperclip"] = 0xf0c6, + ["fa-paragraph"] = 0xf1dd, + ["fa-paste"] = 0xf0ea, + ["fa-pause"] = 0xf04c, + ["fa-pause_circle"] = 0xf28b, + ["fa-pause_circle_o"] = 0xf28c, + ["fa-paw"] = 0xf1b0, + ["fa-paypal"] = 0xf1ed, + ["fa-pencil"] = 0xf040, + ["fa-pencil_square"] = 0xf14b, + ["fa-pencil_square_o"] = 0xf044, + ["fa-percent"] = 0xf295, + ["fa-phone"] = 0xf095, + ["fa-phone_square"] = 0xf098, + ["fa-photo"] = 0xf03e, + ["fa-picture_o"] = 0xf03e, + ["fa-pie_chart"] = 0xf200, + ["fa-pied_piper"] = 0xf2ae, + ["fa-pied_piper_alt"] = 0xf1a8, + ["fa-pied_piper_pp"] = 0xf1a7, + ["fa-pinterest"] = 0xf0d2, + ["fa-pinterest_p"] = 0xf231, + ["fa-pinterest_square"] = 0xf0d3, + ["fa-plane"] = 0xf072, + ["fa-play"] = 0xf04b, + ["fa-play_circle"] = 0xf144, + ["fa-play_circle_o"] = 0xf01d, + ["fa-plug"] = 0xf1e6, + ["fa-plus"] = 0xf067, + ["fa-plus_circle"] = 0xf055, + ["fa-plus_square"] = 0xf0fe, + ["fa-plus_square_o"] = 0xf196, + ["fa-podcast"] = 0xf2ce, + ["fa-power_off"] = 0xf011, + ["fa-print"] = 0xf02f, + ["fa-product_hunt"] = 0xf288, + ["fa-puzzle_piece"] = 0xf12e, + ["fa-qq"] = 0xf1d6, + ["fa-qrcode"] = 0xf029, + ["fa-question"] = 0xf128, + ["fa-question_circle"] = 0xf059, + ["fa-question_circle_o"] = 0xf29c, + ["fa-quora"] = 0xf2c4, + ["fa-quote_left"] = 0xf10d, + ["fa-quote_right"] = 0xf10e, + ["fa-ra"] = 0xf1d0, + ["fa-random"] = 0xf074, + ["fa-ravelry"] = 0xf2d9, + ["fa-rebel"] = 0xf1d0, + ["fa-recycle"] = 0xf1b8, + ["fa-reddit"] = 0xf1a1, + ["fa-reddit_alien"] = 0xf281, + ["fa-reddit_square"] = 0xf1a2, + ["fa-refresh"] = 0xf021, + ["fa-registered"] = 0xf25d, + ["fa-remove"] = 0xf00d, + ["fa-renren"] = 0xf18b, + ["fa-reorder"] = 0xf0c9, + ["fa-repeat"] = 0xf01e, + ["fa-reply"] = 0xf112, + ["fa-reply_all"] = 0xf122, + ["fa-resistance"] = 0xf1d0, + ["fa-retweet"] = 0xf079, + ["fa-rmb"] = 0xf157, + ["fa-road"] = 0xf018, + ["fa-rocket"] = 0xf135, + ["fa-rotate_left"] = 0xf0e2, + ["fa-rotate_right"] = 0xf01e, + ["fa-rouble"] = 0xf158, + ["fa-rss"] = 0xf09e, + ["fa-rss_square"] = 0xf143, + ["fa-rub"] = 0xf158, + ["fa-ruble"] = 0xf158, + ["fa-rupee"] = 0xf156, + ["fa-s15"] = 0xf2cd, + ["fa-safari"] = 0xf267, + ["fa-save"] = 0xf0c7, + ["fa-scissors"] = 0xf0c4, + ["fa-scribd"] = 0xf28a, + ["fa-search"] = 0xf002, + ["fa-search_minus"] = 0xf010, + ["fa-search_plus"] = 0xf00e, + ["fa-sellsy"] = 0xf213, + ["fa-send"] = 0xf1d8, + ["fa-send_o"] = 0xf1d9, + ["fa-server"] = 0xf233, + ["fa-share"] = 0xf064, + ["fa-share_alt"] = 0xf1e0, + ["fa-share_alt_square"] = 0xf1e1, + ["fa-share_square"] = 0xf14d, + ["fa-share_square_o"] = 0xf045, + ["fa-shekel"] = 0xf20b, + ["fa-sheqel"] = 0xf20b, + ["fa-shield"] = 0xf132, + ["fa-ship"] = 0xf21a, + ["fa-shirtsinbulk"] = 0xf214, + ["fa-shopping_bag"] = 0xf290, + ["fa-shopping_basket"] = 0xf291, + ["fa-shopping_cart"] = 0xf07a, + ["fa-shower"] = 0xf2cc, + ["fa-sign_in"] = 0xf090, + ["fa-sign_language"] = 0xf2a7, + ["fa-sign_out"] = 0xf08b, + ["fa-signal"] = 0xf012, + ["fa-signing"] = 0xf2a7, + ["fa-simplybuilt"] = 0xf215, + ["fa-sitemap"] = 0xf0e8, + ["fa-skyatlas"] = 0xf216, + ["fa-skype"] = 0xf17e, + ["fa-slack"] = 0xf198, + ["fa-sliders"] = 0xf1de, + ["fa-slideshare"] = 0xf1e7, + ["fa-smile_o"] = 0xf118, + ["fa-snapchat"] = 0xf2ab, + ["fa-snapchat_ghost"] = 0xf2ac, + ["fa-snapchat_square"] = 0xf2ad, + ["fa-snowflake_o"] = 0xf2dc, + ["fa-soccer_ball_o"] = 0xf1e3, + ["fa-sort"] = 0xf0dc, + ["fa-sort_alpha_asc"] = 0xf15d, + ["fa-sort_alpha_desc"] = 0xf15e, + ["fa-sort_amount_asc"] = 0xf160, + ["fa-sort_amount_desc"] = 0xf161, + ["fa-sort_asc"] = 0xf0de, + ["fa-sort_desc"] = 0xf0dd, + ["fa-sort_down"] = 0xf0dd, + ["fa-sort_numeric_asc"] = 0xf162, + ["fa-sort_numeric_desc"] = 0xf163, + ["fa-sort_up"] = 0xf0de, + ["fa-soundcloud"] = 0xf1be, + ["fa-space_shuttle"] = 0xf197, + ["fa-spinner"] = 0xf110, + ["fa-spoon"] = 0xf1b1, + ["fa-spotify"] = 0xf1bc, + ["fa-square"] = 0xf0c8, + ["fa-square_o"] = 0xf096, + ["fa-stack_exchange"] = 0xf18d, + ["fa-stack_overflow"] = 0xf16c, + ["fa-star"] = 0xf005, + ["fa-star_half"] = 0xf089, + ["fa-star_half_empty"] = 0xf123, + ["fa-star_half_full"] = 0xf123, + ["fa-star_half_o"] = 0xf123, + ["fa-star_o"] = 0xf006, + ["fa-steam"] = 0xf1b6, + ["fa-steam_square"] = 0xf1b7, + ["fa-step_backward"] = 0xf048, + ["fa-step_forward"] = 0xf051, + ["fa-stethoscope"] = 0xf0f1, + ["fa-sticky_note"] = 0xf249, + ["fa-sticky_note_o"] = 0xf24a, + ["fa-stop"] = 0xf04d, + ["fa-stop_circle"] = 0xf28d, + ["fa-stop_circle_o"] = 0xf28e, + ["fa-street_view"] = 0xf21d, + ["fa-strikethrough"] = 0xf0cc, + ["fa-stumbleupon"] = 0xf1a4, + ["fa-stumbleupon_circle"] = 0xf1a3, + ["fa-subscript"] = 0xf12c, + ["fa-subway"] = 0xf239, + ["fa-suitcase"] = 0xf0f2, + ["fa-sun_o"] = 0xf185, + ["fa-superpowers"] = 0xf2dd, + ["fa-superscript"] = 0xf12b, + ["fa-support"] = 0xf1cd, + ["fa-table"] = 0xf0ce, + ["fa-tablet"] = 0xf10a, + ["fa-tachometer"] = 0xf0e4, + ["fa-tag"] = 0xf02b, + ["fa-tags"] = 0xf02c, + ["fa-tasks"] = 0xf0ae, + ["fa-taxi"] = 0xf1ba, + ["fa-telegram"] = 0xf2c6, + ["fa-television"] = 0xf26c, + ["fa-tencent_weibo"] = 0xf1d5, + ["fa-terminal"] = 0xf120, + ["fa-text_height"] = 0xf034, + ["fa-text_width"] = 0xf035, + ["fa-th"] = 0xf00a, + ["fa-th_large"] = 0xf009, + ["fa-th_list"] = 0xf00b, + ["fa-themeisle"] = 0xf2b2, + ["fa-thermometer"] = 0xf2c7, + ["fa-thermometer_0"] = 0xf2cb, + ["fa-thermometer_1"] = 0xf2ca, + ["fa-thermometer_2"] = 0xf2c9, + ["fa-thermometer_3"] = 0xf2c8, + ["fa-thermometer_4"] = 0xf2c7, + ["fa-thermometer_empty"] = 0xf2cb, + ["fa-thermometer_full"] = 0xf2c7, + ["fa-thermometer_half"] = 0xf2c9, + ["fa-thermometer_quarter"] = 0xf2ca, + ["fa-thermometer_three_quarters"] = 0xf2c8, + ["fa-thumb_tack"] = 0xf08d, + ["fa-thumbs_down"] = 0xf165, + ["fa-thumbs_o_down"] = 0xf088, + ["fa-thumbs_o_up"] = 0xf087, + ["fa-thumbs_up"] = 0xf164, + ["fa-ticket"] = 0xf145, + ["fa-times"] = 0xf00d, + ["fa-times_circle"] = 0xf057, + ["fa-times_circle_o"] = 0xf05c, + ["fa-times_rectangle"] = 0xf2d3, + ["fa-times_rectangle_o"] = 0xf2d4, + ["fa-tint"] = 0xf043, + ["fa-toggle_down"] = 0xf150, + ["fa-toggle_left"] = 0xf191, + ["fa-toggle_off"] = 0xf204, + ["fa-toggle_on"] = 0xf205, + ["fa-toggle_right"] = 0xf152, + ["fa-toggle_up"] = 0xf151, + ["fa-trademark"] = 0xf25c, + ["fa-train"] = 0xf238, + ["fa-transgender"] = 0xf224, + ["fa-transgender_alt"] = 0xf225, + ["fa-trash"] = 0xf1f8, + ["fa-trash_o"] = 0xf014, + ["fa-tree"] = 0xf1bb, + ["fa-trello"] = 0xf181, + ["fa-tripadvisor"] = 0xf262, + ["fa-trophy"] = 0xf091, + ["fa-truck"] = 0xf0d1, + ["fa-try"] = 0xf195, + ["fa-tty"] = 0xf1e4, + ["fa-tumblr"] = 0xf173, + ["fa-tumblr_square"] = 0xf174, + ["fa-turkish_lira"] = 0xf195, + ["fa-tv"] = 0xf26c, + ["fa-twitch"] = 0xf1e8, + ["fa-twitter"] = 0xf099, + ["fa-twitter_square"] = 0xf081, + ["fa-umbrella"] = 0xf0e9, + ["fa-underline"] = 0xf0cd, + ["fa-undo"] = 0xf0e2, + ["fa-universal_access"] = 0xf29a, + ["fa-university"] = 0xf19c, + ["fa-unlink"] = 0xf127, + ["fa-unlock"] = 0xf09c, + ["fa-unlock_alt"] = 0xf13e, + ["fa-unsorted"] = 0xf0dc, + ["fa-upload"] = 0xf093, + ["fa-usb"] = 0xf287, + ["fa-usd"] = 0xf155, + ["fa-user"] = 0xf007, + ["fa-user_circle"] = 0xf2bd, + ["fa-user_circle_o"] = 0xf2be, + ["fa-user_md"] = 0xf0f0, + ["fa-user_o"] = 0xf2c0, + ["fa-user_plus"] = 0xf234, + ["fa-user_secret"] = 0xf21b, + ["fa-user_times"] = 0xf235, + ["fa-users"] = 0xf0c0, + ["fa-vcard"] = 0xf2bb, + ["fa-vcard_o"] = 0xf2bc, + ["fa-venus"] = 0xf221, + ["fa-venus_double"] = 0xf226, + ["fa-venus_mars"] = 0xf228, + ["fa-viacoin"] = 0xf237, + ["fa-viadeo"] = 0xf2a9, + ["fa-viadeo_square"] = 0xf2aa, + ["fa-video_camera"] = 0xf03d, + ["fa-vimeo"] = 0xf27d, + ["fa-vimeo_square"] = 0xf194, + ["fa-vine"] = 0xf1ca, + ["fa-vk"] = 0xf189, + ["fa-volume_control_phone"] = 0xf2a0, + ["fa-volume_down"] = 0xf027, + ["fa-volume_off"] = 0xf026, + ["fa-volume_up"] = 0xf028, + ["fa-warning"] = 0xf071, + ["fa-wechat"] = 0xf1d7, + ["fa-weibo"] = 0xf18a, + ["fa-weixin"] = 0xf1d7, + ["fa-whatsapp"] = 0xf232, + ["fa-wheelchair"] = 0xf193, + ["fa-wheelchair_alt"] = 0xf29b, + ["fa-wifi"] = 0xf1eb, + ["fa-wikipedia_w"] = 0xf266, + ["fa-window_close"] = 0xf2d3, + ["fa-window_close_o"] = 0xf2d4, + ["fa-window_maximize"] = 0xf2d0, + ["fa-window_minimize"] = 0xf2d1, + ["fa-window_restore"] = 0xf2d2, + ["fa-windows"] = 0xf17a, + ["fa-won"] = 0xf159, + ["fa-wordpress"] = 0xf19a, + ["fa-wpbeginner"] = 0xf297, + ["fa-wpexplorer"] = 0xf2de, + ["fa-wpforms"] = 0xf298, + ["fa-wrench"] = 0xf0ad, + ["fa-xing"] = 0xf168, + ["fa-xing_square"] = 0xf169, + ["fa-y_combinator"] = 0xf23b, + ["fa-y_combinator_square"] = 0xf1d4, + ["fa-yahoo"] = 0xf19e, + ["fa-yc"] = 0xf23b, + ["fa-yc_square"] = 0xf1d4, + ["fa-yelp"] = 0xf1e9, + ["fa-yen"] = 0xf157, + ["fa-yoast"] = 0xf2b1, + ["fa-youtube"] = 0xf167, + ["fa-youtube_play"] = 0xf16a, + ["fa-youtube_square"] = 0xf166, + ["fae-apple_fruit"] = 0xe29e, + ["fae-atom"] = 0xe27f, + ["fae-bacteria"] = 0xe280, + ["fae-banana"] = 0xe281, + ["fae-bath"] = 0xe282, + ["fae-bed"] = 0xe283, + ["fae-benzene"] = 0xe284, + ["fae-bigger"] = 0xe285, + ["fae-biohazard"] = 0xe286, + ["fae-blogger_circle"] = 0xe287, + ["fae-blogger_square"] = 0xe288, + ["fae-bones"] = 0xe289, + ["fae-book_open"] = 0xe28a, + ["fae-book_open_o"] = 0xe28b, + ["fae-brain"] = 0xe28c, + ["fae-bread"] = 0xe28d, + ["fae-butterfly"] = 0xe28e, + ["fae-carot"] = 0xe28f, + ["fae-cc_by"] = 0xe290, + ["fae-cc_cc"] = 0xe291, + ["fae-cc_nc"] = 0xe292, + ["fae-cc_nc_eu"] = 0xe293, + ["fae-cc_nc_jp"] = 0xe294, + ["fae-cc_nd"] = 0xe295, + ["fae-cc_remix"] = 0xe296, + ["fae-cc_sa"] = 0xe297, + ["fae-cc_share"] = 0xe298, + ["fae-cc_zero"] = 0xe299, + ["fae-checklist_o"] = 0xe29a, + ["fae-cheese"] = 0xe264, + ["fae-cherry"] = 0xe29b, + ["fae-chess_bishop"] = 0xe29c, + ["fae-chess_horse"] = 0xe25f, + ["fae-chess_king"] = 0xe260, + ["fae-chess_pawn"] = 0xe261, + ["fae-chess_queen"] = 0xe262, + ["fae-chess_tower"] = 0xe263, + ["fae-chicken_thigh"] = 0xe29f, + ["fae-chilli"] = 0xe265, + ["fae-chip"] = 0xe266, + ["fae-cicling"] = 0xe267, + ["fae-cloud"] = 0xe268, + ["fae-cockroach"] = 0xe269, + ["fae-coffe_beans"] = 0xe26a, + ["fae-coins"] = 0xe26b, + ["fae-comb"] = 0xe26c, + ["fae-comet"] = 0xe26d, + ["fae-crown"] = 0xe26e, + ["fae-cup_coffe"] = 0xe26f, + ["fae-dice"] = 0xe270, + ["fae-disco"] = 0xe271, + ["fae-dna"] = 0xe272, + ["fae-donut"] = 0xe273, + ["fae-dress"] = 0xe274, + ["fae-drop"] = 0xe275, + ["fae-ello"] = 0xe276, + ["fae-envelope_open"] = 0xe277, + ["fae-envelope_open_o"] = 0xe278, + ["fae-equal"] = 0xe279, + ["fae-equal_bigger"] = 0xe27a, + ["fae-feedly"] = 0xe27b, + ["fae-file_export"] = 0xe27c, + ["fae-file_import"] = 0xe27d, + ["fae-fingerprint"] = 0xe23f, + ["fae-floppy"] = 0xe240, + ["fae-footprint"] = 0xe241, + ["fae-freecodecamp"] = 0xe242, + ["fae-galaxy"] = 0xe243, + ["fae-galery"] = 0xe244, + ["fae-gift_card"] = 0xe2a0, + ["fae-glass"] = 0xe245, + ["fae-google_drive"] = 0xe246, + ["fae-google_play"] = 0xe247, + ["fae-gps"] = 0xe248, + ["fae-grav"] = 0xe249, + ["fae-guitar"] = 0xe24a, + ["fae-gut"] = 0xe24b, + ["fae-halter"] = 0xe24c, + ["fae-hamburger"] = 0xe24d, + ["fae-hat"] = 0xe24e, + ["fae-hexagon"] = 0xe24f, + ["fae-high_heel"] = 0xe250, + ["fae-hotdog"] = 0xe251, + ["fae-ice_cream"] = 0xe252, + ["fae-id_card"] = 0xe253, + ["fae-imdb"] = 0xe254, + ["fae-infinity"] = 0xe255, + ["fae-injection"] = 0xe2a1, + ["fae-isle"] = 0xe2a2, + ["fae-java"] = 0xe256, + ["fae-layers"] = 0xe257, + ["fae-lips"] = 0xe258, + ["fae-lipstick"] = 0xe259, + ["fae-liver"] = 0xe25a, + ["fae-lollipop"] = 0xe2a3, + ["fae-loyalty_card"] = 0xe2a4, + ["fae-lung"] = 0xe25b, + ["fae-makeup_brushes"] = 0xe25c, + ["fae-maximize"] = 0xe25d, + ["fae-meat"] = 0xe2a5, + ["fae-medicine"] = 0xe221, + ["fae-microscope"] = 0xe222, + ["fae-milk_bottle"] = 0xe223, + ["fae-minimize"] = 0xe224, + ["fae-molecule"] = 0xe225, + ["fae-moon_cloud"] = 0xe226, + ["fae-mountains"] = 0xe2a6, + ["fae-mushroom"] = 0xe227, + ["fae-mustache"] = 0xe228, + ["fae-mysql"] = 0xe229, + ["fae-nintendo"] = 0xe22a, + ["fae-orange"] = 0xe2a7, + ["fae-palette_color"] = 0xe22b, + ["fae-peach"] = 0xe2a8, + ["fae-pear"] = 0xe2a9, + ["fae-pi"] = 0xe22c, + ["fae-pizza"] = 0xe22d, + ["fae-planet"] = 0xe22e, + ["fae-plant"] = 0xe22f, + ["fae-playstation"] = 0xe230, + ["fae-poison"] = 0xe231, + ["fae-popcorn"] = 0xe232, + ["fae-popsicle"] = 0xe233, + ["fae-pulse"] = 0xe234, + ["fae-python"] = 0xe235, + ["fae-quora_circle"] = 0xe236, + ["fae-quora_square"] = 0xe237, + ["fae-radioactive"] = 0xe238, + ["fae-raining"] = 0xe239, + ["fae-real_heart"] = 0xe23a, + ["fae-refrigerator"] = 0xe23b, + ["fae-restore"] = 0xe23c, + ["fae-ring"] = 0xe23d, + ["fae-ruby"] = 0xe23e, + ["fae-ruby_o"] = 0xe21e, + ["fae-ruler"] = 0xe21f, + ["fae-shirt"] = 0xe218, + ["fae-slash"] = 0xe216, + ["fae-smaller"] = 0xe200, + ["fae-snowing"] = 0xe201, + ["fae-soda"] = 0xe202, + ["fae-sofa"] = 0xe203, + ["fae-soup"] = 0xe204, + ["fae-spermatozoon"] = 0xe205, + ["fae-spin_double"] = 0xe206, + ["fae-stomach"] = 0xe207, + ["fae-storm"] = 0xe208, + ["fae-sun_cloud"] = 0xe21d, + ["fae-sushi"] = 0xe21a, + ["fae-tacos"] = 0xe219, + ["fae-telegram"] = 0xe217, + ["fae-telegram_circle"] = 0xe215, + ["fae-telescope"] = 0xe209, + ["fae-thermometer"] = 0xe20a, + ["fae-thermometer_high"] = 0xe20b, + ["fae-thermometer_low"] = 0xe20c, + ["fae-thin_close"] = 0xe20d, + ["fae-toilet"] = 0xe20e, + ["fae-tools"] = 0xe20f, + ["fae-tooth"] = 0xe210, + ["fae-tree"] = 0xe21c, + ["fae-triangle_ruler"] = 0xe21b, + ["fae-umbrella"] = 0xe220, + ["fae-uterus"] = 0xe211, + ["fae-virus"] = 0xe214, + ["fae-w3c"] = 0xe212, + ["fae-walking"] = 0xe213, + ["fae-wallet"] = 0xe25e, + ["fae-wind"] = 0xe27e, + ["fae-xbox"] = 0xe29d, + ["iec-power"] = 0x23fb, + ["iec-power_off"] = 0x2b58, + ["iec-power_on"] = 0x23fd, + ["iec-sleep_mode"] = 0x23fe, + ["iec-toggle_power"] = 0x23fc, + ["indent-dotted_guide"] = 0xe621, + ["indent-line"] = 0xe621, + ["indentation-line"] = 0xe621, + ["linux-almalinux"] = 0xf31d, + ["linux-alpine"] = 0xf300, + ["linux-aosc"] = 0xf301, + ["linux-apple"] = 0xf302, + ["linux-archcraft"] = 0xf345, + ["linux-archlabs"] = 0xf31e, + ["linux-archlinux"] = 0xf303, + ["linux-arcolinux"] = 0xf346, + ["linux-arduino"] = 0xf34b, + ["linux-artix"] = 0xf31f, + ["linux-awesome"] = 0xf354, + ["linux-biglinux"] = 0xf347, + ["linux-bspwm"] = 0xf355, + ["linux-budgie"] = 0xf320, + ["linux-centos"] = 0xf304, + ["linux-cinnamon"] = 0xf35f, + ["linux-codeberg"] = 0xf330, + ["linux-coreos"] = 0xf305, + ["linux-crystal"] = 0xf348, + ["linux-debian"] = 0xf306, + ["linux-deepin"] = 0xf321, + ["linux-devuan"] = 0xf307, + ["linux-docker"] = 0xf308, + ["linux-dwm"] = 0xf356, + ["linux-elementary"] = 0xf309, + ["linux-endeavour"] = 0xf322, + ["linux-enlightenment"] = 0xf357, + ["linux-fdroid"] = 0xf36a, + ["linux-fedora"] = 0xf30a, + ["linux-fedora_inverse"] = 0xf30b, + ["linux-ferris"] = 0xf323, + ["linux-flathub"] = 0xf324, + ["linux-fluxbox"] = 0xf358, + ["linux-forgejo"] = 0xf335, + ["linux-fosdem"] = 0xf36b, + ["linux-freebsd"] = 0xf30c, + ["linux-freecad"] = 0xf336, + ["linux-freedesktop"] = 0xf360, + ["linux-garuda"] = 0xf337, + ["linux-gentoo"] = 0xf30d, + ["linux-gimp"] = 0xf338, + ["linux-gitea"] = 0xf339, + ["linux-gnome"] = 0xf361, + ["linux-gnu_guix"] = 0xf325, + ["linux-gtk"] = 0xf362, + ["linux-hyperbola"] = 0xf33a, + ["linux-hyprland"] = 0xf359, + ["linux-i3"] = 0xf35a, + ["linux-illumos"] = 0xf326, + ["linux-inkscape"] = 0xf33b, + ["linux-jwm"] = 0xf35b, + ["linux-kali_linux"] = 0xf327, + ["linux-kde_neon"] = 0xf331, + ["linux-kde_plasma"] = 0xf332, + ["linux-kdenlive"] = 0xf33c, + ["linux-kicad"] = 0xf34c, + ["linux-krita"] = 0xf33d, + ["linux-kubuntu"] = 0xf333, + ["linux-kubuntu_inverse"] = 0xf334, + ["linux-linuxmint"] = 0xf30e, + ["linux-linuxmint_inverse"] = 0xf30f, + ["linux-locos"] = 0xf349, + ["linux-lxde"] = 0xf363, + ["linux-lxle"] = 0xf33e, + ["linux-lxqt"] = 0xf364, + ["linux-mageia"] = 0xf310, + ["linux-mandriva"] = 0xf311, + ["linux-manjaro"] = 0xf312, + ["linux-mate"] = 0xf365, + ["linux-mpv"] = 0xf36e, + ["linux-mxlinux"] = 0xf33f, + ["linux-neovim"] = 0xf36f, + ["linux-nixos"] = 0xf313, + ["linux-octoprint"] = 0xf34d, + ["linux-openbsd"] = 0xf328, + ["linux-openscad"] = 0xf34e, + ["linux-opensuse"] = 0xf314, + ["linux-osh"] = 0xf34f, + ["linux-oshwa"] = 0xf350, + ["linux-osi"] = 0xf36c, + ["linux-parabola"] = 0xf340, + ["linux-parrot"] = 0xf329, + ["linux-pop_os"] = 0xf32a, + ["linux-prusaslicer"] = 0xf351, + ["linux-puppy"] = 0xf341, + ["linux-qtile"] = 0xf35c, + ["linux-qubesos"] = 0xf342, + ["linux-raspberry_pi"] = 0xf315, + ["linux-redhat"] = 0xf316, + ["linux-reprap"] = 0xf352, + ["linux-riscv"] = 0xf353, + ["linux-rocky_linux"] = 0xf32b, + ["linux-sabayon"] = 0xf317, + ["linux-slackware"] = 0xf318, + ["linux-slackware_inverse"] = 0xf319, + ["linux-snappy"] = 0xf32c, + ["linux-solus"] = 0xf32d, + ["linux-sway"] = 0xf35d, + ["linux-tails"] = 0xf343, + ["linux-thunderbird"] = 0xf370, + ["linux-tor"] = 0xf371, + ["linux-trisquel"] = 0xf344, + ["linux-tux"] = 0xf31a, + ["linux-ubuntu"] = 0xf31b, + ["linux-ubuntu_inverse"] = 0xf31c, + ["linux-vanilla"] = 0xf366, + ["linux-void"] = 0xf32e, + ["linux-vscodium"] = 0xf372, + ["linux-wayland"] = 0xf367, + ["linux-wikimedia"] = 0xf36d, + ["linux-xerolinux"] = 0xf34a, + ["linux-xfce"] = 0xf368, + ["linux-xmonad"] = 0xf35e, + ["linux-xorg"] = 0xf369, + ["linux-zorin"] = 0xf32f, + ["md-ab_testing"] = 0xf01c9, + ["md-abacus"] = 0xf16e0, + ["md-abjad_arabic"] = 0xf1328, + ["md-abjad_hebrew"] = 0xf1329, + ["md-abugida_devanagari"] = 0xf132a, + ["md-abugida_thai"] = 0xf132b, + ["md-access_point"] = 0xf0003, + ["md-access_point_check"] = 0xf1538, + ["md-access_point_minus"] = 0xf1539, + ["md-access_point_network"] = 0xf0002, + ["md-access_point_network_off"] = 0xf0be1, + ["md-access_point_off"] = 0xf1511, + ["md-access_point_plus"] = 0xf153a, + ["md-access_point_remove"] = 0xf153b, + ["md-account"] = 0xf0004, + ["md-account_alert"] = 0xf0005, + ["md-account_alert_outline"] = 0xf0b50, + ["md-account_arrow_down"] = 0xf1868, + ["md-account_arrow_down_outline"] = 0xf1869, + ["md-account_arrow_left"] = 0xf0b51, + ["md-account_arrow_left_outline"] = 0xf0b52, + ["md-account_arrow_right"] = 0xf0b53, + ["md-account_arrow_right_outline"] = 0xf0b54, + ["md-account_arrow_up"] = 0xf1867, + ["md-account_arrow_up_outline"] = 0xf186a, + ["md-account_box"] = 0xf0006, + ["md-account_box_multiple"] = 0xf0934, + ["md-account_box_multiple_outline"] = 0xf100a, + ["md-account_box_outline"] = 0xf0007, + ["md-account_cancel"] = 0xf12df, + ["md-account_cancel_outline"] = 0xf12e0, + ["md-account_cash"] = 0xf1097, + ["md-account_cash_outline"] = 0xf1098, + ["md-account_check"] = 0xf0008, + ["md-account_check_outline"] = 0xf0be2, + ["md-account_child"] = 0xf0a89, + ["md-account_child_circle"] = 0xf0a8a, + ["md-account_child_outline"] = 0xf10c8, + ["md-account_circle"] = 0xf0009, + ["md-account_circle_outline"] = 0xf0b55, + ["md-account_clock"] = 0xf0b56, + ["md-account_clock_outline"] = 0xf0b57, + ["md-account_cog"] = 0xf1370, + ["md-account_cog_outline"] = 0xf1371, + ["md-account_convert"] = 0xf000a, + ["md-account_convert_outline"] = 0xf1301, + ["md-account_cowboy_hat"] = 0xf0e9b, + ["md-account_cowboy_hat_outline"] = 0xf17f3, + ["md-account_details"] = 0xf0631, + ["md-account_details_outline"] = 0xf1372, + ["md-account_edit"] = 0xf06bc, + ["md-account_edit_outline"] = 0xf0ffb, + ["md-account_eye"] = 0xf0420, + ["md-account_eye_outline"] = 0xf127b, + ["md-account_filter"] = 0xf0936, + ["md-account_filter_outline"] = 0xf0f9d, + ["md-account_group"] = 0xf0849, + ["md-account_group_outline"] = 0xf0b58, + ["md-account_hard_hat"] = 0xf05b5, + ["md-account_hard_hat_outline"] = 0xf1a1f, + ["md-account_heart"] = 0xf0899, + ["md-account_heart_outline"] = 0xf0be3, + ["md-account_injury"] = 0xf1815, + ["md-account_injury_outline"] = 0xf1816, + ["md-account_key"] = 0xf000b, + ["md-account_key_outline"] = 0xf0be4, + ["md-account_lock"] = 0xf115e, + ["md-account_lock_open"] = 0xf1960, + ["md-account_lock_open_outline"] = 0xf1961, + ["md-account_lock_outline"] = 0xf115f, + ["md-account_minus"] = 0xf000d, + ["md-account_minus_outline"] = 0xf0aec, + ["md-account_multiple"] = 0xf000e, + ["md-account_multiple_check"] = 0xf08c5, + ["md-account_multiple_check_outline"] = 0xf11fe, + ["md-account_multiple_minus"] = 0xf05d3, + ["md-account_multiple_minus_outline"] = 0xf0be5, + ["md-account_multiple_outline"] = 0xf000f, + ["md-account_multiple_plus"] = 0xf0010, + ["md-account_multiple_plus_outline"] = 0xf0800, + ["md-account_multiple_remove"] = 0xf120a, + ["md-account_multiple_remove_outline"] = 0xf120b, + ["md-account_music"] = 0xf0803, + ["md-account_music_outline"] = 0xf0ce9, + ["md-account_network"] = 0xf0011, + ["md-account_network_outline"] = 0xf0be6, + ["md-account_off"] = 0xf0012, + ["md-account_off_outline"] = 0xf0be7, + ["md-account_outline"] = 0xf0013, + ["md-account_plus"] = 0xf0014, + ["md-account_plus_outline"] = 0xf0801, + ["md-account_question"] = 0xf0b59, + ["md-account_question_outline"] = 0xf0b5a, + ["md-account_reactivate"] = 0xf152b, + ["md-account_reactivate_outline"] = 0xf152c, + ["md-account_remove"] = 0xf0015, + ["md-account_remove_outline"] = 0xf0aed, + ["md-account_school"] = 0xf1a20, + ["md-account_school_outline"] = 0xf1a21, + ["md-account_search"] = 0xf0016, + ["md-account_search_outline"] = 0xf0935, + ["md-account_settings"] = 0xf0630, + ["md-account_settings_outline"] = 0xf10c9, + ["md-account_star"] = 0xf0017, + ["md-account_star_outline"] = 0xf0be8, + ["md-account_supervisor"] = 0xf0a8b, + ["md-account_supervisor_circle"] = 0xf0a8c, + ["md-account_supervisor_circle_outline"] = 0xf14ec, + ["md-account_supervisor_outline"] = 0xf112d, + ["md-account_switch"] = 0xf0019, + ["md-account_switch_outline"] = 0xf04cb, + ["md-account_sync"] = 0xf191b, + ["md-account_sync_outline"] = 0xf191c, + ["md-account_tie"] = 0xf0ce3, + ["md-account_tie_hat"] = 0xf1898, + ["md-account_tie_hat_outline"] = 0xf1899, + ["md-account_tie_outline"] = 0xf10ca, + ["md-account_tie_voice"] = 0xf1308, + ["md-account_tie_voice_off"] = 0xf130a, + ["md-account_tie_voice_off_outline"] = 0xf130b, + ["md-account_tie_voice_outline"] = 0xf1309, + ["md-account_tie_woman"] = 0xf1a8c, + ["md-account_voice"] = 0xf05cb, + ["md-account_voice_off"] = 0xf0ed4, + ["md-account_wrench"] = 0xf189a, + ["md-account_wrench_outline"] = 0xf189b, + ["md-adjust"] = 0xf001a, + ["md-advertisements"] = 0xf192a, + ["md-advertisements_off"] = 0xf192b, + ["md-air_conditioner"] = 0xf001b, + ["md-air_filter"] = 0xf0d43, + ["md-air_horn"] = 0xf0dac, + ["md-air_humidifier"] = 0xf1099, + ["md-air_humidifier_off"] = 0xf1466, + ["md-air_purifier"] = 0xf0d44, + ["md-airbag"] = 0xf0be9, + ["md-airballoon"] = 0xf001c, + ["md-airballoon_outline"] = 0xf100b, + ["md-airplane"] = 0xf001d, + ["md-airplane_alert"] = 0xf187a, + ["md-airplane_check"] = 0xf187b, + ["md-airplane_clock"] = 0xf187c, + ["md-airplane_cog"] = 0xf187d, + ["md-airplane_edit"] = 0xf187e, + ["md-airplane_landing"] = 0xf05d4, + ["md-airplane_marker"] = 0xf187f, + ["md-airplane_minus"] = 0xf1880, + ["md-airplane_off"] = 0xf001e, + ["md-airplane_plus"] = 0xf1881, + ["md-airplane_remove"] = 0xf1882, + ["md-airplane_search"] = 0xf1883, + ["md-airplane_settings"] = 0xf1884, + ["md-airplane_takeoff"] = 0xf05d5, + ["md-airport"] = 0xf084b, + ["md-alarm"] = 0xf0020, + ["md-alarm_bell"] = 0xf078e, + ["md-alarm_check"] = 0xf0021, + ["md-alarm_light"] = 0xf078f, + ["md-alarm_light_off"] = 0xf171e, + ["md-alarm_light_off_outline"] = 0xf171f, + ["md-alarm_light_outline"] = 0xf0bea, + ["md-alarm_multiple"] = 0xf0022, + ["md-alarm_note"] = 0xf0e71, + ["md-alarm_note_off"] = 0xf0e72, + ["md-alarm_off"] = 0xf0023, + ["md-alarm_panel"] = 0xf15c4, + ["md-alarm_panel_outline"] = 0xf15c5, + ["md-alarm_plus"] = 0xf0024, + ["md-alarm_snooze"] = 0xf068e, + ["md-album"] = 0xf0025, + ["md-alert"] = 0xf0026, + ["md-alert_box"] = 0xf0027, + ["md-alert_box_outline"] = 0xf0ce4, + ["md-alert_circle"] = 0xf0028, + ["md-alert_circle_check"] = 0xf11ed, + ["md-alert_circle_check_outline"] = 0xf11ee, + ["md-alert_circle_outline"] = 0xf05d6, + ["md-alert_decagram"] = 0xf06bd, + ["md-alert_decagram_outline"] = 0xf0ce5, + ["md-alert_minus"] = 0xf14bb, + ["md-alert_minus_outline"] = 0xf14be, + ["md-alert_octagon"] = 0xf0029, + ["md-alert_octagon_outline"] = 0xf0ce6, + ["md-alert_octagram"] = 0xf0767, + ["md-alert_octagram_outline"] = 0xf0ce7, + ["md-alert_outline"] = 0xf002a, + ["md-alert_plus"] = 0xf14ba, + ["md-alert_plus_outline"] = 0xf14bd, + ["md-alert_remove"] = 0xf14bc, + ["md-alert_remove_outline"] = 0xf14bf, + ["md-alert_rhombus"] = 0xf11ce, + ["md-alert_rhombus_outline"] = 0xf11cf, + ["md-alien"] = 0xf089a, + ["md-alien_outline"] = 0xf10cb, + ["md-align_horizontal_center"] = 0xf11c3, + ["md-align_horizontal_distribute"] = 0xf1962, + ["md-align_horizontal_left"] = 0xf11c2, + ["md-align_horizontal_right"] = 0xf11c4, + ["md-align_vertical_bottom"] = 0xf11c5, + ["md-align_vertical_center"] = 0xf11c6, + ["md-align_vertical_distribute"] = 0xf1963, + ["md-align_vertical_top"] = 0xf11c7, + ["md-all_inclusive"] = 0xf06be, + ["md-all_inclusive_box"] = 0xf188d, + ["md-all_inclusive_box_outline"] = 0xf188e, + ["md-allergy"] = 0xf1258, + ["md-alpha"] = 0xf002b, + ["md-alpha_a"] = 0xf0aee, + ["md-alpha_a_box"] = 0xf0b08, + ["md-alpha_a_box_outline"] = 0xf0beb, + ["md-alpha_a_circle"] = 0xf0bec, + ["md-alpha_a_circle_outline"] = 0xf0bed, + ["md-alpha_b"] = 0xf0aef, + ["md-alpha_b_box"] = 0xf0b09, + ["md-alpha_b_box_outline"] = 0xf0bee, + ["md-alpha_b_circle"] = 0xf0bef, + ["md-alpha_b_circle_outline"] = 0xf0bf0, + ["md-alpha_c"] = 0xf0af0, + ["md-alpha_c_box"] = 0xf0b0a, + ["md-alpha_c_box_outline"] = 0xf0bf1, + ["md-alpha_c_circle"] = 0xf0bf2, + ["md-alpha_c_circle_outline"] = 0xf0bf3, + ["md-alpha_d"] = 0xf0af1, + ["md-alpha_d_box"] = 0xf0b0b, + ["md-alpha_d_box_outline"] = 0xf0bf4, + ["md-alpha_d_circle"] = 0xf0bf5, + ["md-alpha_d_circle_outline"] = 0xf0bf6, + ["md-alpha_e"] = 0xf0af2, + ["md-alpha_e_box"] = 0xf0b0c, + ["md-alpha_e_box_outline"] = 0xf0bf7, + ["md-alpha_e_circle"] = 0xf0bf8, + ["md-alpha_e_circle_outline"] = 0xf0bf9, + ["md-alpha_f"] = 0xf0af3, + ["md-alpha_f_box"] = 0xf0b0d, + ["md-alpha_f_box_outline"] = 0xf0bfa, + ["md-alpha_f_circle"] = 0xf0bfb, + ["md-alpha_f_circle_outline"] = 0xf0bfc, + ["md-alpha_g"] = 0xf0af4, + ["md-alpha_g_box"] = 0xf0b0e, + ["md-alpha_g_box_outline"] = 0xf0bfd, + ["md-alpha_g_circle"] = 0xf0bfe, + ["md-alpha_g_circle_outline"] = 0xf0bff, + ["md-alpha_h"] = 0xf0af5, + ["md-alpha_h_box"] = 0xf0b0f, + ["md-alpha_h_box_outline"] = 0xf0c00, + ["md-alpha_h_circle"] = 0xf0c01, + ["md-alpha_h_circle_outline"] = 0xf0c02, + ["md-alpha_i"] = 0xf1088, + ["md-alpha_i_box"] = 0xf0b10, + ["md-alpha_i_box_outline"] = 0xf0c03, + ["md-alpha_i_circle"] = 0xf0c04, + ["md-alpha_i_circle_outline"] = 0xf0c05, + ["md-alpha_j"] = 0xf0af7, + ["md-alpha_j_box"] = 0xf0b11, + ["md-alpha_j_box_outline"] = 0xf0c06, + ["md-alpha_j_circle"] = 0xf0c07, + ["md-alpha_j_circle_outline"] = 0xf0c08, + ["md-alpha_k"] = 0xf0af8, + ["md-alpha_k_box"] = 0xf0b12, + ["md-alpha_k_box_outline"] = 0xf0c09, + ["md-alpha_k_circle"] = 0xf0c0a, + ["md-alpha_k_circle_outline"] = 0xf0c0b, + ["md-alpha_l"] = 0xf13a6, + ["md-alpha_l_box"] = 0xf0b13, + ["md-alpha_l_box_outline"] = 0xf0c0c, + ["md-alpha_l_circle"] = 0xf0c0d, + ["md-alpha_l_circle_outline"] = 0xf0c0e, + ["md-alpha_m"] = 0xf0afa, + ["md-alpha_m_box"] = 0xf0b14, + ["md-alpha_m_box_outline"] = 0xf0c0f, + ["md-alpha_m_circle"] = 0xf0c10, + ["md-alpha_m_circle_outline"] = 0xf0c11, + ["md-alpha_n"] = 0xf0afb, + ["md-alpha_n_box"] = 0xf0b15, + ["md-alpha_n_box_outline"] = 0xf0c12, + ["md-alpha_n_circle"] = 0xf0c13, + ["md-alpha_n_circle_outline"] = 0xf0c14, + ["md-alpha_o"] = 0xf0b39, + ["md-alpha_o_box"] = 0xf0b16, + ["md-alpha_o_box_outline"] = 0xf0c15, + ["md-alpha_o_circle"] = 0xf0c9e, + ["md-alpha_o_circle_outline"] = 0xf0c9f, + ["md-alpha_p"] = 0xf0afd, + ["md-alpha_p_box"] = 0xf0b17, + ["md-alpha_p_box_outline"] = 0xf0c18, + ["md-alpha_p_circle"] = 0xf0c19, + ["md-alpha_p_circle_outline"] = 0xf0c1a, + ["md-alpha_q"] = 0xf0afe, + ["md-alpha_q_box"] = 0xf0b18, + ["md-alpha_q_box_outline"] = 0xf0c1b, + ["md-alpha_q_circle"] = 0xf0c1c, + ["md-alpha_q_circle_outline"] = 0xf0c1d, + ["md-alpha_r"] = 0xf0aff, + ["md-alpha_r_box"] = 0xf0b19, + ["md-alpha_r_box_outline"] = 0xf0c1e, + ["md-alpha_r_circle"] = 0xf0c1f, + ["md-alpha_r_circle_outline"] = 0xf0c20, + ["md-alpha_s"] = 0xf0b00, + ["md-alpha_s_box"] = 0xf0b1a, + ["md-alpha_s_box_outline"] = 0xf0c21, + ["md-alpha_s_circle"] = 0xf0c22, + ["md-alpha_s_circle_outline"] = 0xf0c23, + ["md-alpha_t"] = 0xf0b01, + ["md-alpha_t_box"] = 0xf0b1b, + ["md-alpha_t_box_outline"] = 0xf0c24, + ["md-alpha_t_circle"] = 0xf0c25, + ["md-alpha_t_circle_outline"] = 0xf0c26, + ["md-alpha_u"] = 0xf0b02, + ["md-alpha_u_box"] = 0xf0b1c, + ["md-alpha_u_box_outline"] = 0xf0c27, + ["md-alpha_u_circle"] = 0xf0c28, + ["md-alpha_u_circle_outline"] = 0xf0c29, + ["md-alpha_v"] = 0xf108c, + ["md-alpha_v_box"] = 0xf0b1d, + ["md-alpha_v_box_outline"] = 0xf0c2a, + ["md-alpha_v_circle"] = 0xf0c2b, + ["md-alpha_v_circle_outline"] = 0xf0c2c, + ["md-alpha_w"] = 0xf0b04, + ["md-alpha_w_box"] = 0xf0b1e, + ["md-alpha_w_box_outline"] = 0xf0c2d, + ["md-alpha_w_circle"] = 0xf0c2e, + ["md-alpha_w_circle_outline"] = 0xf0c2f, + ["md-alpha_x"] = 0xf1091, + ["md-alpha_x_box"] = 0xf0b1f, + ["md-alpha_x_box_outline"] = 0xf0c30, + ["md-alpha_x_circle"] = 0xf0c31, + ["md-alpha_x_circle_outline"] = 0xf0c32, + ["md-alpha_y"] = 0xf0b06, + ["md-alpha_y_box"] = 0xf0b20, + ["md-alpha_y_box_outline"] = 0xf0c33, + ["md-alpha_y_circle"] = 0xf0c34, + ["md-alpha_y_circle_outline"] = 0xf0c35, + ["md-alpha_z"] = 0xf0b07, + ["md-alpha_z_box"] = 0xf0b21, + ["md-alpha_z_box_outline"] = 0xf0c36, + ["md-alpha_z_circle"] = 0xf0c37, + ["md-alpha_z_circle_outline"] = 0xf0c38, + ["md-alphabet_aurebesh"] = 0xf132c, + ["md-alphabet_cyrillic"] = 0xf132d, + ["md-alphabet_greek"] = 0xf132e, + ["md-alphabet_latin"] = 0xf132f, + ["md-alphabet_piqad"] = 0xf1330, + ["md-alphabet_tengwar"] = 0xf1337, + ["md-alphabetical"] = 0xf002c, + ["md-alphabetical_off"] = 0xf100c, + ["md-alphabetical_variant"] = 0xf100d, + ["md-alphabetical_variant_off"] = 0xf100e, + ["md-altimeter"] = 0xf05d7, + ["md-ambulance"] = 0xf002f, + ["md-ammunition"] = 0xf0ce8, + ["md-ampersand"] = 0xf0a8d, + ["md-amplifier"] = 0xf0030, + ["md-amplifier_off"] = 0xf11b5, + ["md-anchor"] = 0xf0031, + ["md-android"] = 0xf0032, + ["md-android_messages"] = 0xf0d45, + ["md-android_studio"] = 0xf0034, + ["md-angle_acute"] = 0xf0937, + ["md-angle_obtuse"] = 0xf0938, + ["md-angle_right"] = 0xf0939, + ["md-angular"] = 0xf06b2, + ["md-angularjs"] = 0xf06bf, + ["md-animation"] = 0xf05d8, + ["md-animation_outline"] = 0xf0a8f, + ["md-animation_play"] = 0xf093a, + ["md-animation_play_outline"] = 0xf0a90, + ["md-ansible"] = 0xf109a, + ["md-antenna"] = 0xf1119, + ["md-anvil"] = 0xf089b, + ["md-apache_kafka"] = 0xf100f, + ["md-api"] = 0xf109b, + ["md-api_off"] = 0xf1257, + ["md-apple"] = 0xf0035, + ["md-apple_finder"] = 0xf0036, + ["md-apple_icloud"] = 0xf0038, + ["md-apple_ios"] = 0xf0037, + ["md-apple_keyboard_caps"] = 0xf0632, + ["md-apple_keyboard_command"] = 0xf0633, + ["md-apple_keyboard_control"] = 0xf0634, + ["md-apple_keyboard_option"] = 0xf0635, + ["md-apple_keyboard_shift"] = 0xf0636, + ["md-apple_safari"] = 0xf0039, + ["md-application"] = 0xf08c6, + ["md-application_array"] = 0xf10f5, + ["md-application_array_outline"] = 0xf10f6, + ["md-application_braces"] = 0xf10f7, + ["md-application_braces_outline"] = 0xf10f8, + ["md-application_brackets"] = 0xf0c8b, + ["md-application_brackets_outline"] = 0xf0c8c, + ["md-application_cog"] = 0xf0675, + ["md-application_cog_outline"] = 0xf1577, + ["md-application_edit"] = 0xf00ae, + ["md-application_edit_outline"] = 0xf0619, + ["md-application_export"] = 0xf0dad, + ["md-application_import"] = 0xf0dae, + ["md-application_outline"] = 0xf0614, + ["md-application_parentheses"] = 0xf10f9, + ["md-application_parentheses_outline"] = 0xf10fa, + ["md-application_settings"] = 0xf0b60, + ["md-application_settings_outline"] = 0xf1555, + ["md-application_variable"] = 0xf10fb, + ["md-application_variable_outline"] = 0xf10fc, + ["md-approximately_equal"] = 0xf0f9e, + ["md-approximately_equal_box"] = 0xf0f9f, + ["md-apps"] = 0xf003b, + ["md-apps_box"] = 0xf0d46, + ["md-arch"] = 0xf08c7, + ["md-archive"] = 0xf003c, + ["md-archive_alert"] = 0xf14fd, + ["md-archive_alert_outline"] = 0xf14fe, + ["md-archive_arrow_down"] = 0xf1259, + ["md-archive_arrow_down_outline"] = 0xf125a, + ["md-archive_arrow_up"] = 0xf125b, + ["md-archive_arrow_up_outline"] = 0xf125c, + ["md-archive_cancel"] = 0xf174b, + ["md-archive_cancel_outline"] = 0xf174c, + ["md-archive_check"] = 0xf174d, + ["md-archive_check_outline"] = 0xf174e, + ["md-archive_clock"] = 0xf174f, + ["md-archive_clock_outline"] = 0xf1750, + ["md-archive_cog"] = 0xf1751, + ["md-archive_cog_outline"] = 0xf1752, + ["md-archive_edit"] = 0xf1753, + ["md-archive_edit_outline"] = 0xf1754, + ["md-archive_eye"] = 0xf1755, + ["md-archive_eye_outline"] = 0xf1756, + ["md-archive_lock"] = 0xf1757, + ["md-archive_lock_open"] = 0xf1758, + ["md-archive_lock_open_outline"] = 0xf1759, + ["md-archive_lock_outline"] = 0xf175a, + ["md-archive_marker"] = 0xf175b, + ["md-archive_marker_outline"] = 0xf175c, + ["md-archive_minus"] = 0xf175d, + ["md-archive_minus_outline"] = 0xf175e, + ["md-archive_music"] = 0xf175f, + ["md-archive_music_outline"] = 0xf1760, + ["md-archive_off"] = 0xf1761, + ["md-archive_off_outline"] = 0xf1762, + ["md-archive_outline"] = 0xf120e, + ["md-archive_plus"] = 0xf1763, + ["md-archive_plus_outline"] = 0xf1764, + ["md-archive_refresh"] = 0xf1765, + ["md-archive_refresh_outline"] = 0xf1766, + ["md-archive_remove"] = 0xf1767, + ["md-archive_remove_outline"] = 0xf1768, + ["md-archive_search"] = 0xf1769, + ["md-archive_search_outline"] = 0xf176a, + ["md-archive_settings"] = 0xf176b, + ["md-archive_settings_outline"] = 0xf176c, + ["md-archive_star"] = 0xf176d, + ["md-archive_star_outline"] = 0xf176e, + ["md-archive_sync"] = 0xf176f, + ["md-archive_sync_outline"] = 0xf1770, + ["md-arm_flex"] = 0xf0fd7, + ["md-arm_flex_outline"] = 0xf0fd6, + ["md-arrange_bring_forward"] = 0xf003d, + ["md-arrange_bring_to_front"] = 0xf003e, + ["md-arrange_send_backward"] = 0xf003f, + ["md-arrange_send_to_back"] = 0xf0040, + ["md-arrow_all"] = 0xf0041, + ["md-arrow_bottom_left"] = 0xf0042, + ["md-arrow_bottom_left_bold_box"] = 0xf1964, + ["md-arrow_bottom_left_bold_box_outline"] = 0xf1965, + ["md-arrow_bottom_left_bold_outline"] = 0xf09b7, + ["md-arrow_bottom_left_thick"] = 0xf09b8, + ["md-arrow_bottom_left_thin"] = 0xf19b6, + ["md-arrow_bottom_left_thin_circle_outline"] = 0xf1596, + ["md-arrow_bottom_right"] = 0xf0043, + ["md-arrow_bottom_right_bold_box"] = 0xf1966, + ["md-arrow_bottom_right_bold_box_outline"] = 0xf1967, + ["md-arrow_bottom_right_bold_outline"] = 0xf09b9, + ["md-arrow_bottom_right_thick"] = 0xf09ba, + ["md-arrow_bottom_right_thin"] = 0xf19b7, + ["md-arrow_bottom_right_thin_circle_outline"] = 0xf1595, + ["md-arrow_collapse"] = 0xf0615, + ["md-arrow_collapse_all"] = 0xf0044, + ["md-arrow_collapse_down"] = 0xf0792, + ["md-arrow_collapse_horizontal"] = 0xf084c, + ["md-arrow_collapse_left"] = 0xf0793, + ["md-arrow_collapse_right"] = 0xf0794, + ["md-arrow_collapse_up"] = 0xf0795, + ["md-arrow_collapse_vertical"] = 0xf084d, + ["md-arrow_decision"] = 0xf09bb, + ["md-arrow_decision_auto"] = 0xf09bc, + ["md-arrow_decision_auto_outline"] = 0xf09bd, + ["md-arrow_decision_outline"] = 0xf09be, + ["md-arrow_down"] = 0xf0045, + ["md-arrow_down_bold"] = 0xf072e, + ["md-arrow_down_bold_box"] = 0xf072f, + ["md-arrow_down_bold_box_outline"] = 0xf0730, + ["md-arrow_down_bold_circle"] = 0xf0047, + ["md-arrow_down_bold_circle_outline"] = 0xf0048, + ["md-arrow_down_bold_hexagon_outline"] = 0xf0049, + ["md-arrow_down_bold_outline"] = 0xf09bf, + ["md-arrow_down_box"] = 0xf06c0, + ["md-arrow_down_circle"] = 0xf0cdb, + ["md-arrow_down_circle_outline"] = 0xf0cdc, + ["md-arrow_down_drop_circle"] = 0xf004a, + ["md-arrow_down_drop_circle_outline"] = 0xf004b, + ["md-arrow_down_left"] = 0xf17a1, + ["md-arrow_down_left_bold"] = 0xf17a2, + ["md-arrow_down_right"] = 0xf17a3, + ["md-arrow_down_right_bold"] = 0xf17a4, + ["md-arrow_down_thick"] = 0xf0046, + ["md-arrow_down_thin"] = 0xf19b3, + ["md-arrow_down_thin_circle_outline"] = 0xf1599, + ["md-arrow_expand"] = 0xf0616, + ["md-arrow_expand_all"] = 0xf004c, + ["md-arrow_expand_down"] = 0xf0796, + ["md-arrow_expand_horizontal"] = 0xf084e, + ["md-arrow_expand_left"] = 0xf0797, + ["md-arrow_expand_right"] = 0xf0798, + ["md-arrow_expand_up"] = 0xf0799, + ["md-arrow_expand_vertical"] = 0xf084f, + ["md-arrow_horizontal_lock"] = 0xf115b, + ["md-arrow_left"] = 0xf004d, + ["md-arrow_left_bold"] = 0xf0731, + ["md-arrow_left_bold_box"] = 0xf0732, + ["md-arrow_left_bold_box_outline"] = 0xf0733, + ["md-arrow_left_bold_circle"] = 0xf004f, + ["md-arrow_left_bold_circle_outline"] = 0xf0050, + ["md-arrow_left_bold_hexagon_outline"] = 0xf0051, + ["md-arrow_left_bold_outline"] = 0xf09c0, + ["md-arrow_left_bottom"] = 0xf17a5, + ["md-arrow_left_bottom_bold"] = 0xf17a6, + ["md-arrow_left_box"] = 0xf06c1, + ["md-arrow_left_circle"] = 0xf0cdd, + ["md-arrow_left_circle_outline"] = 0xf0cde, + ["md-arrow_left_drop_circle"] = 0xf0052, + ["md-arrow_left_drop_circle_outline"] = 0xf0053, + ["md-arrow_left_right"] = 0xf0e73, + ["md-arrow_left_right_bold"] = 0xf0e74, + ["md-arrow_left_right_bold_outline"] = 0xf09c1, + ["md-arrow_left_thick"] = 0xf004e, + ["md-arrow_left_thin"] = 0xf19b1, + ["md-arrow_left_thin_circle_outline"] = 0xf159a, + ["md-arrow_left_top"] = 0xf17a7, + ["md-arrow_left_top_bold"] = 0xf17a8, + ["md-arrow_projectile"] = 0xf1840, + ["md-arrow_projectile_multiple"] = 0xf183f, + ["md-arrow_right"] = 0xf0054, + ["md-arrow_right_bold"] = 0xf0734, + ["md-arrow_right_bold_box"] = 0xf0735, + ["md-arrow_right_bold_box_outline"] = 0xf0736, + ["md-arrow_right_bold_circle"] = 0xf0056, + ["md-arrow_right_bold_circle_outline"] = 0xf0057, + ["md-arrow_right_bold_hexagon_outline"] = 0xf0058, + ["md-arrow_right_bold_outline"] = 0xf09c2, + ["md-arrow_right_bottom"] = 0xf17a9, + ["md-arrow_right_bottom_bold"] = 0xf17aa, + ["md-arrow_right_box"] = 0xf06c2, + ["md-arrow_right_circle"] = 0xf0cdf, + ["md-arrow_right_circle_outline"] = 0xf0ce0, + ["md-arrow_right_drop_circle"] = 0xf0059, + ["md-arrow_right_drop_circle_outline"] = 0xf005a, + ["md-arrow_right_thick"] = 0xf0055, + ["md-arrow_right_thin"] = 0xf19b0, + ["md-arrow_right_thin_circle_outline"] = 0xf1598, + ["md-arrow_right_top"] = 0xf17ab, + ["md-arrow_right_top_bold"] = 0xf17ac, + ["md-arrow_split_horizontal"] = 0xf093b, + ["md-arrow_split_vertical"] = 0xf093c, + ["md-arrow_top_left"] = 0xf005b, + ["md-arrow_top_left_bold_box"] = 0xf1968, + ["md-arrow_top_left_bold_box_outline"] = 0xf1969, + ["md-arrow_top_left_bold_outline"] = 0xf09c3, + ["md-arrow_top_left_bottom_right"] = 0xf0e75, + ["md-arrow_top_left_bottom_right_bold"] = 0xf0e76, + ["md-arrow_top_left_thick"] = 0xf09c4, + ["md-arrow_top_left_thin"] = 0xf19b5, + ["md-arrow_top_left_thin_circle_outline"] = 0xf1593, + ["md-arrow_top_right"] = 0xf005c, + ["md-arrow_top_right_bold_box"] = 0xf196a, + ["md-arrow_top_right_bold_box_outline"] = 0xf196b, + ["md-arrow_top_right_bold_outline"] = 0xf09c5, + ["md-arrow_top_right_bottom_left"] = 0xf0e77, + ["md-arrow_top_right_bottom_left_bold"] = 0xf0e78, + ["md-arrow_top_right_thick"] = 0xf09c6, + ["md-arrow_top_right_thin"] = 0xf19b4, + ["md-arrow_top_right_thin_circle_outline"] = 0xf1594, + ["md-arrow_u_down_left"] = 0xf17ad, + ["md-arrow_u_down_left_bold"] = 0xf17ae, + ["md-arrow_u_down_right"] = 0xf17af, + ["md-arrow_u_down_right_bold"] = 0xf17b0, + ["md-arrow_u_left_bottom"] = 0xf17b1, + ["md-arrow_u_left_bottom_bold"] = 0xf17b2, + ["md-arrow_u_left_top"] = 0xf17b3, + ["md-arrow_u_left_top_bold"] = 0xf17b4, + ["md-arrow_u_right_bottom"] = 0xf17b5, + ["md-arrow_u_right_bottom_bold"] = 0xf17b6, + ["md-arrow_u_right_top"] = 0xf17b7, + ["md-arrow_u_right_top_bold"] = 0xf17b8, + ["md-arrow_u_up_left"] = 0xf17b9, + ["md-arrow_u_up_left_bold"] = 0xf17ba, + ["md-arrow_u_up_right"] = 0xf17bb, + ["md-arrow_u_up_right_bold"] = 0xf17bc, + ["md-arrow_up"] = 0xf005d, + ["md-arrow_up_bold"] = 0xf0737, + ["md-arrow_up_bold_box"] = 0xf0738, + ["md-arrow_up_bold_box_outline"] = 0xf0739, + ["md-arrow_up_bold_circle"] = 0xf005f, + ["md-arrow_up_bold_circle_outline"] = 0xf0060, + ["md-arrow_up_bold_hexagon_outline"] = 0xf0061, + ["md-arrow_up_bold_outline"] = 0xf09c7, + ["md-arrow_up_box"] = 0xf06c3, + ["md-arrow_up_circle"] = 0xf0ce1, + ["md-arrow_up_circle_outline"] = 0xf0ce2, + ["md-arrow_up_down"] = 0xf0e79, + ["md-arrow_up_down_bold"] = 0xf0e7a, + ["md-arrow_up_down_bold_outline"] = 0xf09c8, + ["md-arrow_up_drop_circle"] = 0xf0062, + ["md-arrow_up_drop_circle_outline"] = 0xf0063, + ["md-arrow_up_left"] = 0xf17bd, + ["md-arrow_up_left_bold"] = 0xf17be, + ["md-arrow_up_right"] = 0xf17bf, + ["md-arrow_up_right_bold"] = 0xf17c0, + ["md-arrow_up_thick"] = 0xf005e, + ["md-arrow_up_thin"] = 0xf19b2, + ["md-arrow_up_thin_circle_outline"] = 0xf1597, + ["md-arrow_vertical_lock"] = 0xf115c, + ["md-artstation"] = 0xf0b5b, + ["md-aspect_ratio"] = 0xf0a24, + ["md-assistant"] = 0xf0064, + ["md-asterisk"] = 0xf06c4, + ["md-asterisk_circle_outline"] = 0xf1a27, + ["md-at"] = 0xf0065, + ["md-atlassian"] = 0xf0804, + ["md-atm"] = 0xf0d47, + ["md-atom"] = 0xf0768, + ["md-atom_variant"] = 0xf0e7b, + ["md-attachment"] = 0xf0066, + ["md-attachment_check"] = 0xf1ac1, + ["md-attachment_lock"] = 0xf19c4, + ["md-attachment_minus"] = 0xf1ac2, + ["md-attachment_off"] = 0xf1ac3, + ["md-attachment_plus"] = 0xf1ac4, + ["md-attachment_remove"] = 0xf1ac5, + ["md-audio_input_rca"] = 0xf186b, + ["md-audio_input_stereo_minijack"] = 0xf186c, + ["md-audio_input_xlr"] = 0xf186d, + ["md-audio_video"] = 0xf093d, + ["md-audio_video_off"] = 0xf11b6, + ["md-augmented_reality"] = 0xf0850, + ["md-auto_download"] = 0xf137e, + ["md-auto_fix"] = 0xf0068, + ["md-auto_upload"] = 0xf0069, + ["md-autorenew"] = 0xf006a, + ["md-autorenew_off"] = 0xf19e7, + ["md-av_timer"] = 0xf006b, + ["md-aws"] = 0xf0e0f, + ["md-axe"] = 0xf08c8, + ["md-axe_battle"] = 0xf1842, + ["md-axis"] = 0xf0d48, + ["md-axis_arrow"] = 0xf0d49, + ["md-axis_arrow_info"] = 0xf140e, + ["md-axis_arrow_lock"] = 0xf0d4a, + ["md-axis_lock"] = 0xf0d4b, + ["md-axis_x_arrow"] = 0xf0d4c, + ["md-axis_x_arrow_lock"] = 0xf0d4d, + ["md-axis_x_rotate_clockwise"] = 0xf0d4e, + ["md-axis_x_rotate_counterclockwise"] = 0xf0d4f, + ["md-axis_x_y_arrow_lock"] = 0xf0d50, + ["md-axis_y_arrow"] = 0xf0d51, + ["md-axis_y_arrow_lock"] = 0xf0d52, + ["md-axis_y_rotate_clockwise"] = 0xf0d53, + ["md-axis_y_rotate_counterclockwise"] = 0xf0d54, + ["md-axis_z_arrow"] = 0xf0d55, + ["md-axis_z_arrow_lock"] = 0xf0d56, + ["md-axis_z_rotate_clockwise"] = 0xf0d57, + ["md-axis_z_rotate_counterclockwise"] = 0xf0d58, + ["md-babel"] = 0xf0a25, + ["md-baby"] = 0xf006c, + ["md-baby_bottle"] = 0xf0f39, + ["md-baby_bottle_outline"] = 0xf0f3a, + ["md-baby_buggy"] = 0xf13e0, + ["md-baby_carriage"] = 0xf068f, + ["md-baby_carriage_off"] = 0xf0fa0, + ["md-baby_face"] = 0xf0e7c, + ["md-baby_face_outline"] = 0xf0e7d, + ["md-backburger"] = 0xf006d, + ["md-backspace"] = 0xf006e, + ["md-backspace_outline"] = 0xf0b5c, + ["md-backspace_reverse"] = 0xf0e7e, + ["md-backspace_reverse_outline"] = 0xf0e7f, + ["md-backup_restore"] = 0xf006f, + ["md-bacteria"] = 0xf0ed5, + ["md-bacteria_outline"] = 0xf0ed6, + ["md-badge_account"] = 0xf0da7, + ["md-badge_account_alert"] = 0xf0da8, + ["md-badge_account_alert_outline"] = 0xf0da9, + ["md-badge_account_horizontal"] = 0xf0e0d, + ["md-badge_account_horizontal_outline"] = 0xf0e0e, + ["md-badge_account_outline"] = 0xf0daa, + ["md-badminton"] = 0xf0851, + ["md-bag_carry_on"] = 0xf0f3b, + ["md-bag_carry_on_check"] = 0xf0d65, + ["md-bag_carry_on_off"] = 0xf0f3c, + ["md-bag_checked"] = 0xf0f3d, + ["md-bag_personal"] = 0xf0e10, + ["md-bag_personal_off"] = 0xf0e11, + ["md-bag_personal_off_outline"] = 0xf0e12, + ["md-bag_personal_outline"] = 0xf0e13, + ["md-bag_suitcase"] = 0xf158b, + ["md-bag_suitcase_off"] = 0xf158d, + ["md-bag_suitcase_off_outline"] = 0xf158e, + ["md-bag_suitcase_outline"] = 0xf158c, + ["md-baguette"] = 0xf0f3e, + ["md-balcony"] = 0xf1817, + ["md-balloon"] = 0xf0a26, + ["md-ballot"] = 0xf09c9, + ["md-ballot_outline"] = 0xf09ca, + ["md-ballot_recount"] = 0xf0c39, + ["md-ballot_recount_outline"] = 0xf0c3a, + ["md-bandage"] = 0xf0daf, + ["md-bank"] = 0xf0070, + ["md-bank_check"] = 0xf1655, + ["md-bank_minus"] = 0xf0db0, + ["md-bank_off"] = 0xf1656, + ["md-bank_off_outline"] = 0xf1657, + ["md-bank_outline"] = 0xf0e80, + ["md-bank_plus"] = 0xf0db1, + ["md-bank_remove"] = 0xf0db2, + ["md-bank_transfer"] = 0xf0a27, + ["md-bank_transfer_in"] = 0xf0a28, + ["md-bank_transfer_out"] = 0xf0a29, + ["md-barcode"] = 0xf0071, + ["md-barcode_off"] = 0xf1236, + ["md-barcode_scan"] = 0xf0072, + ["md-barley"] = 0xf0073, + ["md-barley_off"] = 0xf0b5d, + ["md-barn"] = 0xf0b5e, + ["md-barrel"] = 0xf0074, + ["md-barrel_outline"] = 0xf1a28, + ["md-baseball"] = 0xf0852, + ["md-baseball_bat"] = 0xf0853, + ["md-baseball_diamond"] = 0xf15ec, + ["md-baseball_diamond_outline"] = 0xf15ed, + ["md-bash"] = 0xf1183, + ["md-basket"] = 0xf0076, + ["md-basket_check"] = 0xf18e5, + ["md-basket_check_outline"] = 0xf18e6, + ["md-basket_fill"] = 0xf0077, + ["md-basket_minus"] = 0xf1523, + ["md-basket_minus_outline"] = 0xf1524, + ["md-basket_off"] = 0xf1525, + ["md-basket_off_outline"] = 0xf1526, + ["md-basket_outline"] = 0xf1181, + ["md-basket_plus"] = 0xf1527, + ["md-basket_plus_outline"] = 0xf1528, + ["md-basket_remove"] = 0xf1529, + ["md-basket_remove_outline"] = 0xf152a, + ["md-basket_unfill"] = 0xf0078, + ["md-basketball"] = 0xf0806, + ["md-basketball_hoop"] = 0xf0c3b, + ["md-basketball_hoop_outline"] = 0xf0c3c, + ["md-bat"] = 0xf0b5f, + ["md-bathtub"] = 0xf1818, + ["md-bathtub_outline"] = 0xf1819, + ["md-battery"] = 0xf0079, + ["md-battery_10"] = 0xf007a, + ["md-battery_10_bluetooth"] = 0xf093e, + ["md-battery_20"] = 0xf007b, + ["md-battery_20_bluetooth"] = 0xf093f, + ["md-battery_30"] = 0xf007c, + ["md-battery_30_bluetooth"] = 0xf0940, + ["md-battery_40"] = 0xf007d, + ["md-battery_40_bluetooth"] = 0xf0941, + ["md-battery_50"] = 0xf007e, + ["md-battery_50_bluetooth"] = 0xf0942, + ["md-battery_60"] = 0xf007f, + ["md-battery_60_bluetooth"] = 0xf0943, + ["md-battery_70"] = 0xf0080, + ["md-battery_70_bluetooth"] = 0xf0944, + ["md-battery_80"] = 0xf0081, + ["md-battery_80_bluetooth"] = 0xf0945, + ["md-battery_90"] = 0xf0082, + ["md-battery_90_bluetooth"] = 0xf0946, + ["md-battery_alert"] = 0xf0083, + ["md-battery_alert_bluetooth"] = 0xf0947, + ["md-battery_alert_variant"] = 0xf10cc, + ["md-battery_alert_variant_outline"] = 0xf10cd, + ["md-battery_arrow_down"] = 0xf17de, + ["md-battery_arrow_down_outline"] = 0xf17df, + ["md-battery_arrow_up"] = 0xf17e0, + ["md-battery_arrow_up_outline"] = 0xf17e1, + ["md-battery_bluetooth"] = 0xf0948, + ["md-battery_bluetooth_variant"] = 0xf0949, + ["md-battery_charging"] = 0xf0084, + ["md-battery_charging_10"] = 0xf089c, + ["md-battery_charging_100"] = 0xf0085, + ["md-battery_charging_20"] = 0xf0086, + ["md-battery_charging_30"] = 0xf0087, + ["md-battery_charging_40"] = 0xf0088, + ["md-battery_charging_50"] = 0xf089d, + ["md-battery_charging_60"] = 0xf0089, + ["md-battery_charging_70"] = 0xf089e, + ["md-battery_charging_80"] = 0xf008a, + ["md-battery_charging_90"] = 0xf008b, + ["md-battery_charging_high"] = 0xf12a6, + ["md-battery_charging_low"] = 0xf12a4, + ["md-battery_charging_medium"] = 0xf12a5, + ["md-battery_charging_outline"] = 0xf089f, + ["md-battery_charging_wireless"] = 0xf0807, + ["md-battery_charging_wireless_10"] = 0xf0808, + ["md-battery_charging_wireless_20"] = 0xf0809, + ["md-battery_charging_wireless_30"] = 0xf080a, + ["md-battery_charging_wireless_40"] = 0xf080b, + ["md-battery_charging_wireless_50"] = 0xf080c, + ["md-battery_charging_wireless_60"] = 0xf080d, + ["md-battery_charging_wireless_70"] = 0xf080e, + ["md-battery_charging_wireless_80"] = 0xf080f, + ["md-battery_charging_wireless_90"] = 0xf0810, + ["md-battery_charging_wireless_alert"] = 0xf0811, + ["md-battery_charging_wireless_outline"] = 0xf0812, + ["md-battery_check"] = 0xf17e2, + ["md-battery_check_outline"] = 0xf17e3, + ["md-battery_clock"] = 0xf19e5, + ["md-battery_clock_outline"] = 0xf19e6, + ["md-battery_heart"] = 0xf120f, + ["md-battery_heart_outline"] = 0xf1210, + ["md-battery_heart_variant"] = 0xf1211, + ["md-battery_high"] = 0xf12a3, + ["md-battery_lock"] = 0xf179c, + ["md-battery_lock_open"] = 0xf179d, + ["md-battery_low"] = 0xf12a1, + ["md-battery_medium"] = 0xf12a2, + ["md-battery_minus"] = 0xf17e4, + ["md-battery_minus_outline"] = 0xf17e5, + ["md-battery_minus_variant"] = 0xf008c, + ["md-battery_negative"] = 0xf008d, + ["md-battery_off"] = 0xf125d, + ["md-battery_off_outline"] = 0xf125e, + ["md-battery_outline"] = 0xf008e, + ["md-battery_plus"] = 0xf17e6, + ["md-battery_plus_outline"] = 0xf17e7, + ["md-battery_plus_variant"] = 0xf008f, + ["md-battery_positive"] = 0xf0090, + ["md-battery_remove"] = 0xf17e8, + ["md-battery_remove_outline"] = 0xf17e9, + ["md-battery_sync"] = 0xf1834, + ["md-battery_sync_outline"] = 0xf1835, + ["md-battery_unknown"] = 0xf0091, + ["md-battery_unknown_bluetooth"] = 0xf094a, + ["md-beach"] = 0xf0092, + ["md-beaker"] = 0xf0cea, + ["md-beaker_alert"] = 0xf1229, + ["md-beaker_alert_outline"] = 0xf122a, + ["md-beaker_check"] = 0xf122b, + ["md-beaker_check_outline"] = 0xf122c, + ["md-beaker_minus"] = 0xf122d, + ["md-beaker_minus_outline"] = 0xf122e, + ["md-beaker_outline"] = 0xf0690, + ["md-beaker_plus"] = 0xf122f, + ["md-beaker_plus_outline"] = 0xf1230, + ["md-beaker_question"] = 0xf1231, + ["md-beaker_question_outline"] = 0xf1232, + ["md-beaker_remove"] = 0xf1233, + ["md-beaker_remove_outline"] = 0xf1234, + ["md-bed"] = 0xf02e3, + ["md-bed_double"] = 0xf0fd4, + ["md-bed_double_outline"] = 0xf0fd3, + ["md-bed_empty"] = 0xf08a0, + ["md-bed_king"] = 0xf0fd2, + ["md-bed_king_outline"] = 0xf0fd1, + ["md-bed_outline"] = 0xf0099, + ["md-bed_queen"] = 0xf0fd0, + ["md-bed_queen_outline"] = 0xf0fdb, + ["md-bed_single"] = 0xf106d, + ["md-bed_single_outline"] = 0xf106e, + ["md-bee"] = 0xf0fa1, + ["md-bee_flower"] = 0xf0fa2, + ["md-beehive_off_outline"] = 0xf13ed, + ["md-beehive_outline"] = 0xf10ce, + ["md-beekeeper"] = 0xf14e2, + ["md-beer"] = 0xf0098, + ["md-beer_outline"] = 0xf130c, + ["md-bell"] = 0xf009a, + ["md-bell_alert"] = 0xf0d59, + ["md-bell_alert_outline"] = 0xf0e81, + ["md-bell_badge"] = 0xf116b, + ["md-bell_badge_outline"] = 0xf0178, + ["md-bell_cancel"] = 0xf13e7, + ["md-bell_cancel_outline"] = 0xf13e8, + ["md-bell_check"] = 0xf11e5, + ["md-bell_check_outline"] = 0xf11e6, + ["md-bell_circle"] = 0xf0d5a, + ["md-bell_circle_outline"] = 0xf0d5b, + ["md-bell_cog"] = 0xf1a29, + ["md-bell_cog_outline"] = 0xf1a2a, + ["md-bell_minus"] = 0xf13e9, + ["md-bell_minus_outline"] = 0xf13ea, + ["md-bell_off"] = 0xf009b, + ["md-bell_off_outline"] = 0xf0a91, + ["md-bell_outline"] = 0xf009c, + ["md-bell_plus"] = 0xf009d, + ["md-bell_plus_outline"] = 0xf0a92, + ["md-bell_remove"] = 0xf13eb, + ["md-bell_remove_outline"] = 0xf13ec, + ["md-bell_ring"] = 0xf009e, + ["md-bell_ring_outline"] = 0xf009f, + ["md-bell_sleep"] = 0xf00a0, + ["md-bell_sleep_outline"] = 0xf0a93, + ["md-beta"] = 0xf00a1, + ["md-betamax"] = 0xf09cb, + ["md-biathlon"] = 0xf0e14, + ["md-bicycle"] = 0xf109c, + ["md-bicycle_basket"] = 0xf1235, + ["md-bicycle_cargo"] = 0xf189c, + ["md-bicycle_electric"] = 0xf15b4, + ["md-bicycle_penny_farthing"] = 0xf15e9, + ["md-bike"] = 0xf00a3, + ["md-bike_fast"] = 0xf111f, + ["md-billboard"] = 0xf1010, + ["md-billiards"] = 0xf0b61, + ["md-billiards_rack"] = 0xf0b62, + ["md-binoculars"] = 0xf00a5, + ["md-bio"] = 0xf00a6, + ["md-biohazard"] = 0xf00a7, + ["md-bird"] = 0xf15c6, + ["md-bitbucket"] = 0xf00a8, + ["md-bitcoin"] = 0xf0813, + ["md-black_mesa"] = 0xf00a9, + ["md-blender"] = 0xf0ceb, + ["md-blender_outline"] = 0xf181a, + ["md-blender_software"] = 0xf00ab, + ["md-blinds"] = 0xf00ac, + ["md-blinds_horizontal"] = 0xf1a2b, + ["md-blinds_horizontal_closed"] = 0xf1a2c, + ["md-blinds_open"] = 0xf1011, + ["md-blinds_vertical"] = 0xf1a2d, + ["md-blinds_vertical_closed"] = 0xf1a2e, + ["md-block_helper"] = 0xf00ad, + ["md-blood_bag"] = 0xf0cec, + ["md-bluetooth"] = 0xf00af, + ["md-bluetooth_audio"] = 0xf00b0, + ["md-bluetooth_connect"] = 0xf00b1, + ["md-bluetooth_off"] = 0xf00b2, + ["md-bluetooth_settings"] = 0xf00b3, + ["md-bluetooth_transfer"] = 0xf00b4, + ["md-blur"] = 0xf00b5, + ["md-blur_linear"] = 0xf00b6, + ["md-blur_off"] = 0xf00b7, + ["md-blur_radial"] = 0xf00b8, + ["md-bolt"] = 0xf0db3, + ["md-bomb"] = 0xf0691, + ["md-bomb_off"] = 0xf06c5, + ["md-bone"] = 0xf00b9, + ["md-bone_off"] = 0xf19e0, + ["md-book"] = 0xf00ba, + ["md-book_account"] = 0xf13ad, + ["md-book_account_outline"] = 0xf13ae, + ["md-book_alert"] = 0xf167c, + ["md-book_alert_outline"] = 0xf167d, + ["md-book_alphabet"] = 0xf061d, + ["md-book_arrow_down"] = 0xf167e, + ["md-book_arrow_down_outline"] = 0xf167f, + ["md-book_arrow_left"] = 0xf1680, + ["md-book_arrow_left_outline"] = 0xf1681, + ["md-book_arrow_right"] = 0xf1682, + ["md-book_arrow_right_outline"] = 0xf1683, + ["md-book_arrow_up"] = 0xf1684, + ["md-book_arrow_up_outline"] = 0xf1685, + ["md-book_cancel"] = 0xf1686, + ["md-book_cancel_outline"] = 0xf1687, + ["md-book_check"] = 0xf14f3, + ["md-book_check_outline"] = 0xf14f4, + ["md-book_clock"] = 0xf1688, + ["md-book_clock_outline"] = 0xf1689, + ["md-book_cog"] = 0xf168a, + ["md-book_cog_outline"] = 0xf168b, + ["md-book_cross"] = 0xf00a2, + ["md-book_edit"] = 0xf168c, + ["md-book_edit_outline"] = 0xf168d, + ["md-book_education"] = 0xf16c9, + ["md-book_education_outline"] = 0xf16ca, + ["md-book_heart"] = 0xf1a1d, + ["md-book_heart_outline"] = 0xf1a1e, + ["md-book_information_variant"] = 0xf106f, + ["md-book_lock"] = 0xf079a, + ["md-book_lock_open"] = 0xf079b, + ["md-book_lock_open_outline"] = 0xf168e, + ["md-book_lock_outline"] = 0xf168f, + ["md-book_marker"] = 0xf1690, + ["md-book_marker_outline"] = 0xf1691, + ["md-book_minus"] = 0xf05d9, + ["md-book_minus_multiple"] = 0xf0a94, + ["md-book_minus_multiple_outline"] = 0xf090b, + ["md-book_minus_outline"] = 0xf1692, + ["md-book_multiple"] = 0xf00bb, + ["md-book_multiple_outline"] = 0xf0436, + ["md-book_music"] = 0xf0067, + ["md-book_music_outline"] = 0xf1693, + ["md-book_off"] = 0xf1694, + ["md-book_off_outline"] = 0xf1695, + ["md-book_open"] = 0xf00bd, + ["md-book_open_blank_variant"] = 0xf00be, + ["md-book_open_outline"] = 0xf0b63, + ["md-book_open_page_variant"] = 0xf05da, + ["md-book_open_page_variant_outline"] = 0xf15d6, + ["md-book_open_variant"] = 0xf14f7, + ["md-book_outline"] = 0xf0b64, + ["md-book_play"] = 0xf0e82, + ["md-book_play_outline"] = 0xf0e83, + ["md-book_plus"] = 0xf05db, + ["md-book_plus_multiple"] = 0xf0a95, + ["md-book_plus_multiple_outline"] = 0xf0ade, + ["md-book_plus_outline"] = 0xf1696, + ["md-book_refresh"] = 0xf1697, + ["md-book_refresh_outline"] = 0xf1698, + ["md-book_remove"] = 0xf0a97, + ["md-book_remove_multiple"] = 0xf0a96, + ["md-book_remove_multiple_outline"] = 0xf04ca, + ["md-book_remove_outline"] = 0xf1699, + ["md-book_search"] = 0xf0e84, + ["md-book_search_outline"] = 0xf0e85, + ["md-book_settings"] = 0xf169a, + ["md-book_settings_outline"] = 0xf169b, + ["md-book_sync"] = 0xf169c, + ["md-book_sync_outline"] = 0xf16c8, + ["md-book_variant"] = 0xf00bf, + ["md-book_variant_multiple"] = 0xf00bc, + ["md-bookmark"] = 0xf00c0, + ["md-bookmark_box_multiple"] = 0xf196c, + ["md-bookmark_box_multiple_outline"] = 0xf196d, + ["md-bookmark_check"] = 0xf00c1, + ["md-bookmark_check_outline"] = 0xf137b, + ["md-bookmark_minus"] = 0xf09cc, + ["md-bookmark_minus_outline"] = 0xf09cd, + ["md-bookmark_multiple"] = 0xf0e15, + ["md-bookmark_multiple_outline"] = 0xf0e16, + ["md-bookmark_music"] = 0xf00c2, + ["md-bookmark_music_outline"] = 0xf1379, + ["md-bookmark_off"] = 0xf09ce, + ["md-bookmark_off_outline"] = 0xf09cf, + ["md-bookmark_outline"] = 0xf00c3, + ["md-bookmark_plus"] = 0xf00c5, + ["md-bookmark_plus_outline"] = 0xf00c4, + ["md-bookmark_remove"] = 0xf00c6, + ["md-bookmark_remove_outline"] = 0xf137a, + ["md-bookshelf"] = 0xf125f, + ["md-boom_gate"] = 0xf0e86, + ["md-boom_gate_alert"] = 0xf0e87, + ["md-boom_gate_alert_outline"] = 0xf0e88, + ["md-boom_gate_arrow_down"] = 0xf0e89, + ["md-boom_gate_arrow_down_outline"] = 0xf0e8a, + ["md-boom_gate_arrow_up"] = 0xf0e8c, + ["md-boom_gate_arrow_up_outline"] = 0xf0e8d, + ["md-boom_gate_outline"] = 0xf0e8b, + ["md-boom_gate_up"] = 0xf17f9, + ["md-boom_gate_up_outline"] = 0xf17fa, + ["md-boombox"] = 0xf05dc, + ["md-boomerang"] = 0xf10cf, + ["md-bootstrap"] = 0xf06c6, + ["md-border_all"] = 0xf00c7, + ["md-border_all_variant"] = 0xf08a1, + ["md-border_bottom"] = 0xf00c8, + ["md-border_bottom_variant"] = 0xf08a2, + ["md-border_color"] = 0xf00c9, + ["md-border_horizontal"] = 0xf00ca, + ["md-border_inside"] = 0xf00cb, + ["md-border_left"] = 0xf00cc, + ["md-border_left_variant"] = 0xf08a3, + ["md-border_none"] = 0xf00cd, + ["md-border_none_variant"] = 0xf08a4, + ["md-border_outside"] = 0xf00ce, + ["md-border_right"] = 0xf00cf, + ["md-border_right_variant"] = 0xf08a5, + ["md-border_style"] = 0xf00d0, + ["md-border_top"] = 0xf00d1, + ["md-border_top_variant"] = 0xf08a6, + ["md-border_vertical"] = 0xf00d2, + ["md-bottle_soda"] = 0xf1070, + ["md-bottle_soda_classic"] = 0xf1071, + ["md-bottle_soda_classic_outline"] = 0xf1363, + ["md-bottle_soda_outline"] = 0xf1072, + ["md-bottle_tonic"] = 0xf112e, + ["md-bottle_tonic_outline"] = 0xf112f, + ["md-bottle_tonic_plus"] = 0xf1130, + ["md-bottle_tonic_plus_outline"] = 0xf1131, + ["md-bottle_tonic_skull"] = 0xf1132, + ["md-bottle_tonic_skull_outline"] = 0xf1133, + ["md-bottle_wine"] = 0xf0854, + ["md-bottle_wine_outline"] = 0xf1310, + ["md-bow_arrow"] = 0xf1841, + ["md-bow_tie"] = 0xf0678, + ["md-bowl"] = 0xf028e, + ["md-bowl_mix"] = 0xf0617, + ["md-bowl_mix_outline"] = 0xf02e4, + ["md-bowl_outline"] = 0xf02a9, + ["md-bowling"] = 0xf00d3, + ["md-box"] = 0xf00d4, + ["md-box_cutter"] = 0xf00d5, + ["md-box_cutter_off"] = 0xf0b4a, + ["md-box_shadow"] = 0xf0637, + ["md-boxing_glove"] = 0xf0b65, + ["md-braille"] = 0xf09d0, + ["md-brain"] = 0xf09d1, + ["md-bread_slice"] = 0xf0cee, + ["md-bread_slice_outline"] = 0xf0cef, + ["md-bridge"] = 0xf0618, + ["md-briefcase"] = 0xf00d6, + ["md-briefcase_account"] = 0xf0cf0, + ["md-briefcase_account_outline"] = 0xf0cf1, + ["md-briefcase_arrow_left_right"] = 0xf1a8d, + ["md-briefcase_arrow_left_right_outline"] = 0xf1a8e, + ["md-briefcase_arrow_up_down"] = 0xf1a8f, + ["md-briefcase_arrow_up_down_outline"] = 0xf1a90, + ["md-briefcase_check"] = 0xf00d7, + ["md-briefcase_check_outline"] = 0xf131e, + ["md-briefcase_clock"] = 0xf10d0, + ["md-briefcase_clock_outline"] = 0xf10d1, + ["md-briefcase_download"] = 0xf00d8, + ["md-briefcase_download_outline"] = 0xf0c3d, + ["md-briefcase_edit"] = 0xf0a98, + ["md-briefcase_edit_outline"] = 0xf0c3e, + ["md-briefcase_eye"] = 0xf17d9, + ["md-briefcase_eye_outline"] = 0xf17da, + ["md-briefcase_minus"] = 0xf0a2a, + ["md-briefcase_minus_outline"] = 0xf0c3f, + ["md-briefcase_off"] = 0xf1658, + ["md-briefcase_off_outline"] = 0xf1659, + ["md-briefcase_outline"] = 0xf0814, + ["md-briefcase_plus"] = 0xf0a2b, + ["md-briefcase_plus_outline"] = 0xf0c40, + ["md-briefcase_remove"] = 0xf0a2c, + ["md-briefcase_remove_outline"] = 0xf0c41, + ["md-briefcase_search"] = 0xf0a2d, + ["md-briefcase_search_outline"] = 0xf0c42, + ["md-briefcase_upload"] = 0xf00d9, + ["md-briefcase_upload_outline"] = 0xf0c43, + ["md-briefcase_variant"] = 0xf1494, + ["md-briefcase_variant_off"] = 0xf165a, + ["md-briefcase_variant_off_outline"] = 0xf165b, + ["md-briefcase_variant_outline"] = 0xf1495, + ["md-brightness_1"] = 0xf00da, + ["md-brightness_2"] = 0xf00db, + ["md-brightness_3"] = 0xf00dc, + ["md-brightness_4"] = 0xf00dd, + ["md-brightness_5"] = 0xf00de, + ["md-brightness_6"] = 0xf00df, + ["md-brightness_7"] = 0xf00e0, + ["md-brightness_auto"] = 0xf00e1, + ["md-brightness_percent"] = 0xf0cf2, + ["md-broadcast"] = 0xf1720, + ["md-broadcast_off"] = 0xf1721, + ["md-broom"] = 0xf00e2, + ["md-brush"] = 0xf00e3, + ["md-brush_off"] = 0xf1771, + ["md-brush_outline"] = 0xf1a0d, + ["md-brush_variant"] = 0xf1813, + ["md-bucket"] = 0xf1415, + ["md-bucket_outline"] = 0xf1416, + ["md-buffet"] = 0xf0578, + ["md-bug"] = 0xf00e4, + ["md-bug_check"] = 0xf0a2e, + ["md-bug_check_outline"] = 0xf0a2f, + ["md-bug_outline"] = 0xf0a30, + ["md-bugle"] = 0xf0db4, + ["md-bulkhead_light"] = 0xf1a2f, + ["md-bulldozer"] = 0xf0b22, + ["md-bullet"] = 0xf0cf3, + ["md-bulletin_board"] = 0xf00e5, + ["md-bullhorn"] = 0xf00e6, + ["md-bullhorn_outline"] = 0xf0b23, + ["md-bullhorn_variant"] = 0xf196e, + ["md-bullhorn_variant_outline"] = 0xf196f, + ["md-bullseye"] = 0xf05dd, + ["md-bullseye_arrow"] = 0xf08c9, + ["md-bulma"] = 0xf12e7, + ["md-bunk_bed"] = 0xf1302, + ["md-bunk_bed_outline"] = 0xf0097, + ["md-bus"] = 0xf00e7, + ["md-bus_alert"] = 0xf0a99, + ["md-bus_articulated_end"] = 0xf079c, + ["md-bus_articulated_front"] = 0xf079d, + ["md-bus_clock"] = 0xf08ca, + ["md-bus_double_decker"] = 0xf079e, + ["md-bus_electric"] = 0xf191d, + ["md-bus_marker"] = 0xf1212, + ["md-bus_multiple"] = 0xf0f3f, + ["md-bus_school"] = 0xf079f, + ["md-bus_side"] = 0xf07a0, + ["md-bus_stop"] = 0xf1012, + ["md-bus_stop_covered"] = 0xf1013, + ["md-bus_stop_uncovered"] = 0xf1014, + ["md-butterfly"] = 0xf1589, + ["md-butterfly_outline"] = 0xf158a, + ["md-cabin_a_frame"] = 0xf188c, + ["md-cable_data"] = 0xf1394, + ["md-cached"] = 0xf00e8, + ["md-cactus"] = 0xf0db5, + ["md-cake"] = 0xf00e9, + ["md-cake_layered"] = 0xf00ea, + ["md-cake_variant"] = 0xf00eb, + ["md-cake_variant_outline"] = 0xf17f0, + ["md-calculator"] = 0xf00ec, + ["md-calculator_variant"] = 0xf0a9a, + ["md-calculator_variant_outline"] = 0xf15a6, + ["md-calendar"] = 0xf00ed, + ["md-calendar_account"] = 0xf0ed7, + ["md-calendar_account_outline"] = 0xf0ed8, + ["md-calendar_alert"] = 0xf0a31, + ["md-calendar_arrow_left"] = 0xf1134, + ["md-calendar_arrow_right"] = 0xf1135, + ["md-calendar_blank"] = 0xf00ee, + ["md-calendar_blank_multiple"] = 0xf1073, + ["md-calendar_blank_outline"] = 0xf0b66, + ["md-calendar_check"] = 0xf00ef, + ["md-calendar_check_outline"] = 0xf0c44, + ["md-calendar_clock"] = 0xf00f0, + ["md-calendar_clock_outline"] = 0xf16e1, + ["md-calendar_collapse_horizontal"] = 0xf189d, + ["md-calendar_cursor"] = 0xf157b, + ["md-calendar_edit"] = 0xf08a7, + ["md-calendar_end"] = 0xf166c, + ["md-calendar_expand_horizontal"] = 0xf189e, + ["md-calendar_export"] = 0xf0b24, + ["md-calendar_heart"] = 0xf09d2, + ["md-calendar_import"] = 0xf0b25, + ["md-calendar_lock"] = 0xf1641, + ["md-calendar_lock_outline"] = 0xf1642, + ["md-calendar_minus"] = 0xf0d5c, + ["md-calendar_month"] = 0xf0e17, + ["md-calendar_month_outline"] = 0xf0e18, + ["md-calendar_multiple"] = 0xf00f1, + ["md-calendar_multiple_check"] = 0xf00f2, + ["md-calendar_multiselect"] = 0xf0a32, + ["md-calendar_outline"] = 0xf0b67, + ["md-calendar_plus"] = 0xf00f3, + ["md-calendar_question"] = 0xf0692, + ["md-calendar_range"] = 0xf0679, + ["md-calendar_range_outline"] = 0xf0b68, + ["md-calendar_refresh"] = 0xf01e1, + ["md-calendar_refresh_outline"] = 0xf0203, + ["md-calendar_remove"] = 0xf00f4, + ["md-calendar_remove_outline"] = 0xf0c45, + ["md-calendar_search"] = 0xf094c, + ["md-calendar_star"] = 0xf09d3, + ["md-calendar_start"] = 0xf166d, + ["md-calendar_sync"] = 0xf0e8e, + ["md-calendar_sync_outline"] = 0xf0e8f, + ["md-calendar_text"] = 0xf00f5, + ["md-calendar_text_outline"] = 0xf0c46, + ["md-calendar_today"] = 0xf00f6, + ["md-calendar_today_outline"] = 0xf1a30, + ["md-calendar_week"] = 0xf0a33, + ["md-calendar_week_begin"] = 0xf0a34, + ["md-calendar_week_begin_outline"] = 0xf1a31, + ["md-calendar_week_end"] = 0xf1a32, + ["md-calendar_week_end_outline"] = 0xf1a33, + ["md-calendar_week_outline"] = 0xf1a34, + ["md-calendar_weekend"] = 0xf0ed9, + ["md-calendar_weekend_outline"] = 0xf0eda, + ["md-call_made"] = 0xf00f7, + ["md-call_merge"] = 0xf00f8, + ["md-call_missed"] = 0xf00f9, + ["md-call_received"] = 0xf00fa, + ["md-call_split"] = 0xf00fb, + ["md-camcorder"] = 0xf00fc, + ["md-camcorder_off"] = 0xf00ff, + ["md-camera"] = 0xf0100, + ["md-camera_account"] = 0xf08cb, + ["md-camera_burst"] = 0xf0693, + ["md-camera_control"] = 0xf0b69, + ["md-camera_document"] = 0xf1871, + ["md-camera_document_off"] = 0xf1872, + ["md-camera_enhance"] = 0xf0101, + ["md-camera_enhance_outline"] = 0xf0b6a, + ["md-camera_flip"] = 0xf15d9, + ["md-camera_flip_outline"] = 0xf15da, + ["md-camera_front"] = 0xf0102, + ["md-camera_front_variant"] = 0xf0103, + ["md-camera_gopro"] = 0xf07a1, + ["md-camera_image"] = 0xf08cc, + ["md-camera_iris"] = 0xf0104, + ["md-camera_lock"] = 0xf1a14, + ["md-camera_lock_outline"] = 0xf1a15, + ["md-camera_marker"] = 0xf19a7, + ["md-camera_marker_outline"] = 0xf19a8, + ["md-camera_metering_center"] = 0xf07a2, + ["md-camera_metering_matrix"] = 0xf07a3, + ["md-camera_metering_partial"] = 0xf07a4, + ["md-camera_metering_spot"] = 0xf07a5, + ["md-camera_off"] = 0xf05df, + ["md-camera_off_outline"] = 0xf19bf, + ["md-camera_outline"] = 0xf0d5d, + ["md-camera_party_mode"] = 0xf0105, + ["md-camera_plus"] = 0xf0edb, + ["md-camera_plus_outline"] = 0xf0edc, + ["md-camera_rear"] = 0xf0106, + ["md-camera_rear_variant"] = 0xf0107, + ["md-camera_retake"] = 0xf0e19, + ["md-camera_retake_outline"] = 0xf0e1a, + ["md-camera_switch"] = 0xf0108, + ["md-camera_switch_outline"] = 0xf084a, + ["md-camera_timer"] = 0xf0109, + ["md-camera_wireless"] = 0xf0db6, + ["md-camera_wireless_outline"] = 0xf0db7, + ["md-campfire"] = 0xf0edd, + ["md-cancel"] = 0xf073a, + ["md-candelabra"] = 0xf17d2, + ["md-candelabra_fire"] = 0xf17d3, + ["md-candle"] = 0xf05e2, + ["md-candy"] = 0xf1970, + ["md-candy_off"] = 0xf1971, + ["md-candy_off_outline"] = 0xf1972, + ["md-candy_outline"] = 0xf1973, + ["md-candycane"] = 0xf010a, + ["md-cannabis"] = 0xf07a6, + ["md-cannabis_off"] = 0xf166e, + ["md-caps_lock"] = 0xf0a9b, + ["md-car"] = 0xf010b, + ["md-car_2_plus"] = 0xf1015, + ["md-car_3_plus"] = 0xf1016, + ["md-car_arrow_left"] = 0xf13b2, + ["md-car_arrow_right"] = 0xf13b3, + ["md-car_back"] = 0xf0e1b, + ["md-car_battery"] = 0xf010c, + ["md-car_brake_abs"] = 0xf0c47, + ["md-car_brake_alert"] = 0xf0c48, + ["md-car_brake_fluid_level"] = 0xf1909, + ["md-car_brake_hold"] = 0xf0d5e, + ["md-car_brake_low_pressure"] = 0xf190a, + ["md-car_brake_parking"] = 0xf0d5f, + ["md-car_brake_retarder"] = 0xf1017, + ["md-car_brake_temperature"] = 0xf190b, + ["md-car_brake_worn_linings"] = 0xf190c, + ["md-car_child_seat"] = 0xf0fa3, + ["md-car_clock"] = 0xf1974, + ["md-car_clutch"] = 0xf1018, + ["md-car_cog"] = 0xf13cc, + ["md-car_connected"] = 0xf010d, + ["md-car_convertible"] = 0xf07a7, + ["md-car_coolant_level"] = 0xf1019, + ["md-car_cruise_control"] = 0xf0d60, + ["md-car_defrost_front"] = 0xf0d61, + ["md-car_defrost_rear"] = 0xf0d62, + ["md-car_door"] = 0xf0b6b, + ["md-car_door_lock"] = 0xf109d, + ["md-car_electric"] = 0xf0b6c, + ["md-car_electric_outline"] = 0xf15b5, + ["md-car_emergency"] = 0xf160f, + ["md-car_esp"] = 0xf0c49, + ["md-car_estate"] = 0xf07a8, + ["md-car_hatchback"] = 0xf07a9, + ["md-car_info"] = 0xf11be, + ["md-car_key"] = 0xf0b6d, + ["md-car_lifted_pickup"] = 0xf152d, + ["md-car_light_alert"] = 0xf190d, + ["md-car_light_dimmed"] = 0xf0c4a, + ["md-car_light_fog"] = 0xf0c4b, + ["md-car_light_high"] = 0xf0c4c, + ["md-car_limousine"] = 0xf08cd, + ["md-car_multiple"] = 0xf0b6e, + ["md-car_off"] = 0xf0e1c, + ["md-car_outline"] = 0xf14ed, + ["md-car_parking_lights"] = 0xf0d63, + ["md-car_pickup"] = 0xf07aa, + ["md-car_seat"] = 0xf0fa4, + ["md-car_seat_cooler"] = 0xf0fa5, + ["md-car_seat_heater"] = 0xf0fa6, + ["md-car_select"] = 0xf1879, + ["md-car_settings"] = 0xf13cd, + ["md-car_shift_pattern"] = 0xf0f40, + ["md-car_side"] = 0xf07ab, + ["md-car_speed_limiter"] = 0xf190e, + ["md-car_sports"] = 0xf07ac, + ["md-car_tire_alert"] = 0xf0c4d, + ["md-car_traction_control"] = 0xf0d64, + ["md-car_turbocharger"] = 0xf101a, + ["md-car_wash"] = 0xf010e, + ["md-car_windshield"] = 0xf101b, + ["md-car_windshield_outline"] = 0xf101c, + ["md-car_wireless"] = 0xf1878, + ["md-car_wrench"] = 0xf1814, + ["md-carabiner"] = 0xf14c0, + ["md-caravan"] = 0xf07ad, + ["md-card"] = 0xf0b6f, + ["md-card_account_details"] = 0xf05d2, + ["md-card_account_details_outline"] = 0xf0dab, + ["md-card_account_details_star"] = 0xf02a3, + ["md-card_account_details_star_outline"] = 0xf06db, + ["md-card_account_mail"] = 0xf018e, + ["md-card_account_mail_outline"] = 0xf0e98, + ["md-card_account_phone"] = 0xf0e99, + ["md-card_account_phone_outline"] = 0xf0e9a, + ["md-card_bulleted"] = 0xf0b70, + ["md-card_bulleted_off"] = 0xf0b71, + ["md-card_bulleted_off_outline"] = 0xf0b72, + ["md-card_bulleted_outline"] = 0xf0b73, + ["md-card_bulleted_settings"] = 0xf0b74, + ["md-card_bulleted_settings_outline"] = 0xf0b75, + ["md-card_minus"] = 0xf1600, + ["md-card_minus_outline"] = 0xf1601, + ["md-card_multiple"] = 0xf17f1, + ["md-card_multiple_outline"] = 0xf17f2, + ["md-card_off"] = 0xf1602, + ["md-card_off_outline"] = 0xf1603, + ["md-card_outline"] = 0xf0b76, + ["md-card_plus"] = 0xf11ff, + ["md-card_plus_outline"] = 0xf1200, + ["md-card_remove"] = 0xf1604, + ["md-card_remove_outline"] = 0xf1605, + ["md-card_search"] = 0xf1074, + ["md-card_search_outline"] = 0xf1075, + ["md-card_text"] = 0xf0b77, + ["md-card_text_outline"] = 0xf0b78, + ["md-cards"] = 0xf0638, + ["md-cards_club"] = 0xf08ce, + ["md-cards_club_outline"] = 0xf189f, + ["md-cards_diamond"] = 0xf08cf, + ["md-cards_diamond_outline"] = 0xf101d, + ["md-cards_outline"] = 0xf0639, + ["md-cards_playing"] = 0xf18a1, + ["md-cards_playing_club"] = 0xf18a2, + ["md-cards_playing_club_multiple"] = 0xf18a3, + ["md-cards_playing_club_multiple_outline"] = 0xf18a4, + ["md-cards_playing_club_outline"] = 0xf18a5, + ["md-cards_playing_diamond"] = 0xf18a6, + ["md-cards_playing_diamond_multiple"] = 0xf18a7, + ["md-cards_playing_diamond_multiple_outline"] = 0xf18a8, + ["md-cards_playing_diamond_outline"] = 0xf18a9, + ["md-cards_playing_heart"] = 0xf18aa, + ["md-cards_playing_heart_multiple"] = 0xf18ab, + ["md-cards_playing_heart_multiple_outline"] = 0xf18ac, + ["md-cards_playing_heart_outline"] = 0xf18ad, + ["md-cards_playing_outline"] = 0xf063a, + ["md-cards_playing_spade"] = 0xf18ae, + ["md-cards_playing_spade_multiple"] = 0xf18af, + ["md-cards_playing_spade_multiple_outline"] = 0xf18b0, + ["md-cards_playing_spade_outline"] = 0xf18b1, + ["md-cards_spade"] = 0xf08d1, + ["md-cards_spade_outline"] = 0xf18b2, + ["md-cards_variant"] = 0xf06c7, + ["md-carrot"] = 0xf010f, + ["md-cart"] = 0xf0110, + ["md-cart_arrow_down"] = 0xf0d66, + ["md-cart_arrow_right"] = 0xf0c4e, + ["md-cart_arrow_up"] = 0xf0d67, + ["md-cart_check"] = 0xf15ea, + ["md-cart_heart"] = 0xf18e0, + ["md-cart_minus"] = 0xf0d68, + ["md-cart_off"] = 0xf066b, + ["md-cart_outline"] = 0xf0111, + ["md-cart_plus"] = 0xf0112, + ["md-cart_remove"] = 0xf0d69, + ["md-cart_variant"] = 0xf15eb, + ["md-case_sensitive_alt"] = 0xf0113, + ["md-cash"] = 0xf0114, + ["md-cash_100"] = 0xf0115, + ["md-cash_check"] = 0xf14ee, + ["md-cash_clock"] = 0xf1a91, + ["md-cash_fast"] = 0xf185c, + ["md-cash_lock"] = 0xf14ea, + ["md-cash_lock_open"] = 0xf14eb, + ["md-cash_marker"] = 0xf0db8, + ["md-cash_minus"] = 0xf1260, + ["md-cash_multiple"] = 0xf0116, + ["md-cash_plus"] = 0xf1261, + ["md-cash_refund"] = 0xf0a9c, + ["md-cash_register"] = 0xf0cf4, + ["md-cash_remove"] = 0xf1262, + ["md-cash_sync"] = 0xf1a92, + ["md-cassette"] = 0xf09d4, + ["md-cast"] = 0xf0118, + ["md-cast_audio"] = 0xf101e, + ["md-cast_audio_variant"] = 0xf1749, + ["md-cast_connected"] = 0xf0119, + ["md-cast_education"] = 0xf0e1d, + ["md-cast_off"] = 0xf078a, + ["md-cast_variant"] = 0xf001f, + ["md-castle"] = 0xf011a, + ["md-cat"] = 0xf011b, + ["md-cctv"] = 0xf07ae, + ["md-cctv_off"] = 0xf185f, + ["md-ceiling_fan"] = 0xf1797, + ["md-ceiling_fan_light"] = 0xf1798, + ["md-ceiling_light"] = 0xf0769, + ["md-ceiling_light_multiple"] = 0xf18dd, + ["md-ceiling_light_multiple_outline"] = 0xf18de, + ["md-ceiling_light_outline"] = 0xf17c7, + ["md-cellphone"] = 0xf011c, + ["md-cellphone_arrow_down"] = 0xf09d5, + ["md-cellphone_arrow_down_variant"] = 0xf19c5, + ["md-cellphone_basic"] = 0xf011e, + ["md-cellphone_charging"] = 0xf1397, + ["md-cellphone_check"] = 0xf17fd, + ["md-cellphone_cog"] = 0xf0951, + ["md-cellphone_dock"] = 0xf011f, + ["md-cellphone_information"] = 0xf0f41, + ["md-cellphone_key"] = 0xf094e, + ["md-cellphone_link"] = 0xf0121, + ["md-cellphone_link_off"] = 0xf0122, + ["md-cellphone_lock"] = 0xf094f, + ["md-cellphone_marker"] = 0xf183a, + ["md-cellphone_message"] = 0xf08d3, + ["md-cellphone_message_off"] = 0xf10d2, + ["md-cellphone_nfc"] = 0xf0e90, + ["md-cellphone_nfc_off"] = 0xf12d8, + ["md-cellphone_off"] = 0xf0950, + ["md-cellphone_play"] = 0xf101f, + ["md-cellphone_remove"] = 0xf094d, + ["md-cellphone_screenshot"] = 0xf0a35, + ["md-cellphone_settings"] = 0xf0123, + ["md-cellphone_sound"] = 0xf0952, + ["md-cellphone_text"] = 0xf08d2, + ["md-cellphone_wireless"] = 0xf0815, + ["md-centos"] = 0xf111a, + ["md-certificate"] = 0xf0124, + ["md-certificate_outline"] = 0xf1188, + ["md-chair_rolling"] = 0xf0f48, + ["md-chair_school"] = 0xf0125, + ["md-chandelier"] = 0xf1793, + ["md-charity"] = 0xf0c4f, + ["md-chart_arc"] = 0xf0126, + ["md-chart_areaspline"] = 0xf0127, + ["md-chart_areaspline_variant"] = 0xf0e91, + ["md-chart_bar"] = 0xf0128, + ["md-chart_bar_stacked"] = 0xf076a, + ["md-chart_bell_curve"] = 0xf0c50, + ["md-chart_bell_curve_cumulative"] = 0xf0fa7, + ["md-chart_box"] = 0xf154d, + ["md-chart_box_outline"] = 0xf154e, + ["md-chart_box_plus_outline"] = 0xf154f, + ["md-chart_bubble"] = 0xf05e3, + ["md-chart_donut"] = 0xf07af, + ["md-chart_donut_variant"] = 0xf07b0, + ["md-chart_gantt"] = 0xf066c, + ["md-chart_histogram"] = 0xf0129, + ["md-chart_line"] = 0xf012a, + ["md-chart_line_stacked"] = 0xf076b, + ["md-chart_line_variant"] = 0xf07b1, + ["md-chart_multiline"] = 0xf08d4, + ["md-chart_multiple"] = 0xf1213, + ["md-chart_pie"] = 0xf012b, + ["md-chart_ppf"] = 0xf1380, + ["md-chart_sankey"] = 0xf11df, + ["md-chart_sankey_variant"] = 0xf11e0, + ["md-chart_scatter_plot"] = 0xf0e92, + ["md-chart_scatter_plot_hexbin"] = 0xf066d, + ["md-chart_timeline"] = 0xf066e, + ["md-chart_timeline_variant"] = 0xf0e93, + ["md-chart_timeline_variant_shimmer"] = 0xf15b6, + ["md-chart_tree"] = 0xf0e94, + ["md-chart_waterfall"] = 0xf1918, + ["md-chat"] = 0xf0b79, + ["md-chat_alert"] = 0xf0b7a, + ["md-chat_alert_outline"] = 0xf12c9, + ["md-chat_minus"] = 0xf1410, + ["md-chat_minus_outline"] = 0xf1413, + ["md-chat_outline"] = 0xf0ede, + ["md-chat_plus"] = 0xf140f, + ["md-chat_plus_outline"] = 0xf1412, + ["md-chat_processing"] = 0xf0b7b, + ["md-chat_processing_outline"] = 0xf12ca, + ["md-chat_question"] = 0xf1738, + ["md-chat_question_outline"] = 0xf1739, + ["md-chat_remove"] = 0xf1411, + ["md-chat_remove_outline"] = 0xf1414, + ["md-chat_sleep"] = 0xf12d1, + ["md-chat_sleep_outline"] = 0xf12d2, + ["md-check"] = 0xf012c, + ["md-check_all"] = 0xf012d, + ["md-check_bold"] = 0xf0e1e, + ["md-check_circle"] = 0xf05e0, + ["md-check_circle_outline"] = 0xf05e1, + ["md-check_decagram"] = 0xf0791, + ["md-check_decagram_outline"] = 0xf1740, + ["md-check_network"] = 0xf0c53, + ["md-check_network_outline"] = 0xf0c54, + ["md-check_outline"] = 0xf0855, + ["md-check_underline"] = 0xf0e1f, + ["md-check_underline_circle"] = 0xf0e20, + ["md-check_underline_circle_outline"] = 0xf0e21, + ["md-checkbook"] = 0xf0a9d, + ["md-checkbox_blank"] = 0xf012e, + ["md-checkbox_blank_badge"] = 0xf1176, + ["md-checkbox_blank_badge_outline"] = 0xf0117, + ["md-checkbox_blank_circle"] = 0xf0765, + ["md-checkbox_blank_circle_outline"] = 0xf0766, + ["md-checkbox_blank_off"] = 0xf12ec, + ["md-checkbox_blank_off_outline"] = 0xf12ed, + ["md-checkbox_blank_outline"] = 0xf0131, + ["md-checkbox_intermediate"] = 0xf0856, + ["md-checkbox_marked"] = 0xf0132, + ["md-checkbox_marked_circle"] = 0xf0133, + ["md-checkbox_marked_circle_outline"] = 0xf0134, + ["md-checkbox_marked_circle_plus_outline"] = 0xf1927, + ["md-checkbox_marked_outline"] = 0xf0135, + ["md-checkbox_multiple_blank"] = 0xf0136, + ["md-checkbox_multiple_blank_circle"] = 0xf063b, + ["md-checkbox_multiple_blank_circle_outline"] = 0xf063c, + ["md-checkbox_multiple_blank_outline"] = 0xf0137, + ["md-checkbox_multiple_marked"] = 0xf0138, + ["md-checkbox_multiple_marked_circle"] = 0xf063d, + ["md-checkbox_multiple_marked_circle_outline"] = 0xf063e, + ["md-checkbox_multiple_marked_outline"] = 0xf0139, + ["md-checkbox_multiple_outline"] = 0xf0c51, + ["md-checkbox_outline"] = 0xf0c52, + ["md-checkerboard"] = 0xf013a, + ["md-checkerboard_minus"] = 0xf1202, + ["md-checkerboard_plus"] = 0xf1201, + ["md-checkerboard_remove"] = 0xf1203, + ["md-cheese"] = 0xf12b9, + ["md-cheese_off"] = 0xf13ee, + ["md-chef_hat"] = 0xf0b7c, + ["md-chemical_weapon"] = 0xf013b, + ["md-chess_bishop"] = 0xf085c, + ["md-chess_king"] = 0xf0857, + ["md-chess_knight"] = 0xf0858, + ["md-chess_pawn"] = 0xf0859, + ["md-chess_queen"] = 0xf085a, + ["md-chess_rook"] = 0xf085b, + ["md-chevron_double_down"] = 0xf013c, + ["md-chevron_double_left"] = 0xf013d, + ["md-chevron_double_right"] = 0xf013e, + ["md-chevron_double_up"] = 0xf013f, + ["md-chevron_down"] = 0xf0140, + ["md-chevron_down_box"] = 0xf09d6, + ["md-chevron_down_box_outline"] = 0xf09d7, + ["md-chevron_down_circle"] = 0xf0b26, + ["md-chevron_down_circle_outline"] = 0xf0b27, + ["md-chevron_left"] = 0xf0141, + ["md-chevron_left_box"] = 0xf09d8, + ["md-chevron_left_box_outline"] = 0xf09d9, + ["md-chevron_left_circle"] = 0xf0b28, + ["md-chevron_left_circle_outline"] = 0xf0b29, + ["md-chevron_right"] = 0xf0142, + ["md-chevron_right_box"] = 0xf09da, + ["md-chevron_right_box_outline"] = 0xf09db, + ["md-chevron_right_circle"] = 0xf0b2a, + ["md-chevron_right_circle_outline"] = 0xf0b2b, + ["md-chevron_triple_down"] = 0xf0db9, + ["md-chevron_triple_left"] = 0xf0dba, + ["md-chevron_triple_right"] = 0xf0dbb, + ["md-chevron_triple_up"] = 0xf0dbc, + ["md-chevron_up"] = 0xf0143, + ["md-chevron_up_box"] = 0xf09dc, + ["md-chevron_up_box_outline"] = 0xf09dd, + ["md-chevron_up_circle"] = 0xf0b2c, + ["md-chevron_up_circle_outline"] = 0xf0b2d, + ["md-chili_alert"] = 0xf17ea, + ["md-chili_alert_outline"] = 0xf17eb, + ["md-chili_hot"] = 0xf07b2, + ["md-chili_hot_outline"] = 0xf17ec, + ["md-chili_medium"] = 0xf07b3, + ["md-chili_medium_outline"] = 0xf17ed, + ["md-chili_mild"] = 0xf07b4, + ["md-chili_mild_outline"] = 0xf17ee, + ["md-chili_off"] = 0xf1467, + ["md-chili_off_outline"] = 0xf17ef, + ["md-chip"] = 0xf061a, + ["md-church"] = 0xf0144, + ["md-cigar"] = 0xf1189, + ["md-cigar_off"] = 0xf141b, + ["md-circle_box"] = 0xf15dc, + ["md-circle_box_outline"] = 0xf15dd, + ["md-circle_double"] = 0xf0e95, + ["md-circle_edit_outline"] = 0xf08d5, + ["md-circle_expand"] = 0xf0e96, + ["md-circle_half"] = 0xf1395, + ["md-circle_half_full"] = 0xf1396, + ["md-circle_medium"] = 0xf09de, + ["md-circle_multiple"] = 0xf0b38, + ["md-circle_multiple_outline"] = 0xf0695, + ["md-circle_off_outline"] = 0xf10d3, + ["md-circle_opacity"] = 0xf1853, + ["md-circle_slice_1"] = 0xf0a9e, + ["md-circle_slice_2"] = 0xf0a9f, + ["md-circle_slice_3"] = 0xf0aa0, + ["md-circle_slice_4"] = 0xf0aa1, + ["md-circle_slice_5"] = 0xf0aa2, + ["md-circle_slice_6"] = 0xf0aa3, + ["md-circle_slice_7"] = 0xf0aa4, + ["md-circle_slice_8"] = 0xf0aa5, + ["md-circle_small"] = 0xf09df, + ["md-circular_saw"] = 0xf0e22, + ["md-city"] = 0xf0146, + ["md-city_variant"] = 0xf0a36, + ["md-city_variant_outline"] = 0xf0a37, + ["md-clipboard"] = 0xf0147, + ["md-clipboard_account"] = 0xf0148, + ["md-clipboard_account_outline"] = 0xf0c55, + ["md-clipboard_alert"] = 0xf0149, + ["md-clipboard_alert_outline"] = 0xf0cf7, + ["md-clipboard_arrow_down"] = 0xf014a, + ["md-clipboard_arrow_down_outline"] = 0xf0c56, + ["md-clipboard_arrow_left"] = 0xf014b, + ["md-clipboard_arrow_left_outline"] = 0xf0cf8, + ["md-clipboard_arrow_right"] = 0xf0cf9, + ["md-clipboard_arrow_right_outline"] = 0xf0cfa, + ["md-clipboard_arrow_up"] = 0xf0c57, + ["md-clipboard_arrow_up_outline"] = 0xf0c58, + ["md-clipboard_check"] = 0xf014e, + ["md-clipboard_check_multiple"] = 0xf1263, + ["md-clipboard_check_multiple_outline"] = 0xf1264, + ["md-clipboard_check_outline"] = 0xf08a8, + ["md-clipboard_clock"] = 0xf16e2, + ["md-clipboard_clock_outline"] = 0xf16e3, + ["md-clipboard_edit"] = 0xf14e5, + ["md-clipboard_edit_outline"] = 0xf14e6, + ["md-clipboard_file"] = 0xf1265, + ["md-clipboard_file_outline"] = 0xf1266, + ["md-clipboard_flow"] = 0xf06c8, + ["md-clipboard_flow_outline"] = 0xf1117, + ["md-clipboard_list"] = 0xf10d4, + ["md-clipboard_list_outline"] = 0xf10d5, + ["md-clipboard_minus"] = 0xf1618, + ["md-clipboard_minus_outline"] = 0xf1619, + ["md-clipboard_multiple"] = 0xf1267, + ["md-clipboard_multiple_outline"] = 0xf1268, + ["md-clipboard_off"] = 0xf161a, + ["md-clipboard_off_outline"] = 0xf161b, + ["md-clipboard_outline"] = 0xf014c, + ["md-clipboard_play"] = 0xf0c59, + ["md-clipboard_play_multiple"] = 0xf1269, + ["md-clipboard_play_multiple_outline"] = 0xf126a, + ["md-clipboard_play_outline"] = 0xf0c5a, + ["md-clipboard_plus"] = 0xf0751, + ["md-clipboard_plus_outline"] = 0xf131f, + ["md-clipboard_pulse"] = 0xf085d, + ["md-clipboard_pulse_outline"] = 0xf085e, + ["md-clipboard_remove"] = 0xf161c, + ["md-clipboard_remove_outline"] = 0xf161d, + ["md-clipboard_search"] = 0xf161e, + ["md-clipboard_search_outline"] = 0xf161f, + ["md-clipboard_text"] = 0xf014d, + ["md-clipboard_text_clock"] = 0xf18f9, + ["md-clipboard_text_clock_outline"] = 0xf18fa, + ["md-clipboard_text_multiple"] = 0xf126b, + ["md-clipboard_text_multiple_outline"] = 0xf126c, + ["md-clipboard_text_off"] = 0xf1620, + ["md-clipboard_text_off_outline"] = 0xf1621, + ["md-clipboard_text_outline"] = 0xf0a38, + ["md-clipboard_text_play"] = 0xf0c5b, + ["md-clipboard_text_play_outline"] = 0xf0c5c, + ["md-clipboard_text_search"] = 0xf1622, + ["md-clipboard_text_search_outline"] = 0xf1623, + ["md-clippy"] = 0xf014f, + ["md-clock"] = 0xf0954, + ["md-clock_alert"] = 0xf0955, + ["md-clock_alert_outline"] = 0xf05ce, + ["md-clock_check"] = 0xf0fa8, + ["md-clock_check_outline"] = 0xf0fa9, + ["md-clock_digital"] = 0xf0e97, + ["md-clock_edit"] = 0xf19ba, + ["md-clock_edit_outline"] = 0xf19bb, + ["md-clock_end"] = 0xf0151, + ["md-clock_fast"] = 0xf0152, + ["md-clock_in"] = 0xf0153, + ["md-clock_minus"] = 0xf1863, + ["md-clock_minus_outline"] = 0xf1864, + ["md-clock_out"] = 0xf0154, + ["md-clock_outline"] = 0xf0150, + ["md-clock_plus"] = 0xf1861, + ["md-clock_plus_outline"] = 0xf1862, + ["md-clock_remove"] = 0xf1865, + ["md-clock_remove_outline"] = 0xf1866, + ["md-clock_start"] = 0xf0155, + ["md-clock_time_eight"] = 0xf1446, + ["md-clock_time_eight_outline"] = 0xf1452, + ["md-clock_time_eleven"] = 0xf1449, + ["md-clock_time_eleven_outline"] = 0xf1455, + ["md-clock_time_five"] = 0xf1443, + ["md-clock_time_five_outline"] = 0xf144f, + ["md-clock_time_four"] = 0xf1442, + ["md-clock_time_four_outline"] = 0xf144e, + ["md-clock_time_nine"] = 0xf1447, + ["md-clock_time_nine_outline"] = 0xf1453, + ["md-clock_time_one"] = 0xf143f, + ["md-clock_time_one_outline"] = 0xf144b, + ["md-clock_time_seven"] = 0xf1445, + ["md-clock_time_seven_outline"] = 0xf1451, + ["md-clock_time_six"] = 0xf1444, + ["md-clock_time_six_outline"] = 0xf1450, + ["md-clock_time_ten"] = 0xf1448, + ["md-clock_time_ten_outline"] = 0xf1454, + ["md-clock_time_three"] = 0xf1441, + ["md-clock_time_three_outline"] = 0xf144d, + ["md-clock_time_twelve"] = 0xf144a, + ["md-clock_time_twelve_outline"] = 0xf1456, + ["md-clock_time_two"] = 0xf1440, + ["md-clock_time_two_outline"] = 0xf144c, + ["md-close"] = 0xf0156, + ["md-close_box"] = 0xf0157, + ["md-close_box_multiple"] = 0xf0c5d, + ["md-close_box_multiple_outline"] = 0xf0c5e, + ["md-close_box_outline"] = 0xf0158, + ["md-close_circle"] = 0xf0159, + ["md-close_circle_multiple"] = 0xf062a, + ["md-close_circle_multiple_outline"] = 0xf0883, + ["md-close_circle_outline"] = 0xf015a, + ["md-close_network"] = 0xf015b, + ["md-close_network_outline"] = 0xf0c5f, + ["md-close_octagon"] = 0xf015c, + ["md-close_octagon_outline"] = 0xf015d, + ["md-close_outline"] = 0xf06c9, + ["md-close_thick"] = 0xf1398, + ["md-closed_caption"] = 0xf015e, + ["md-closed_caption_outline"] = 0xf0dbd, + ["md-cloud"] = 0xf015f, + ["md-cloud_alert"] = 0xf09e0, + ["md-cloud_braces"] = 0xf07b5, + ["md-cloud_check"] = 0xf0160, + ["md-cloud_check_outline"] = 0xf12cc, + ["md-cloud_circle"] = 0xf0161, + ["md-cloud_download"] = 0xf0162, + ["md-cloud_download_outline"] = 0xf0b7d, + ["md-cloud_lock"] = 0xf11f1, + ["md-cloud_lock_outline"] = 0xf11f2, + ["md-cloud_off_outline"] = 0xf0164, + ["md-cloud_outline"] = 0xf0163, + ["md-cloud_percent"] = 0xf1a35, + ["md-cloud_percent_outline"] = 0xf1a36, + ["md-cloud_print"] = 0xf0165, + ["md-cloud_print_outline"] = 0xf0166, + ["md-cloud_question"] = 0xf0a39, + ["md-cloud_refresh"] = 0xf052a, + ["md-cloud_search"] = 0xf0956, + ["md-cloud_search_outline"] = 0xf0957, + ["md-cloud_sync"] = 0xf063f, + ["md-cloud_sync_outline"] = 0xf12d6, + ["md-cloud_tags"] = 0xf07b6, + ["md-cloud_upload"] = 0xf0167, + ["md-cloud_upload_outline"] = 0xf0b7e, + ["md-clover"] = 0xf0816, + ["md-coach_lamp"] = 0xf1020, + ["md-coach_lamp_variant"] = 0xf1a37, + ["md-coat_rack"] = 0xf109e, + ["md-code_array"] = 0xf0168, + ["md-code_braces"] = 0xf0169, + ["md-code_braces_box"] = 0xf10d6, + ["md-code_brackets"] = 0xf016a, + ["md-code_equal"] = 0xf016b, + ["md-code_greater_than"] = 0xf016c, + ["md-code_greater_than_or_equal"] = 0xf016d, + ["md-code_json"] = 0xf0626, + ["md-code_less_than"] = 0xf016e, + ["md-code_less_than_or_equal"] = 0xf016f, + ["md-code_not_equal"] = 0xf0170, + ["md-code_not_equal_variant"] = 0xf0171, + ["md-code_parentheses"] = 0xf0172, + ["md-code_parentheses_box"] = 0xf10d7, + ["md-code_string"] = 0xf0173, + ["md-code_tags"] = 0xf0174, + ["md-code_tags_check"] = 0xf0694, + ["md-codepen"] = 0xf0175, + ["md-coffee"] = 0xf0176, + ["md-coffee_maker"] = 0xf109f, + ["md-coffee_maker_check"] = 0xf1931, + ["md-coffee_maker_check_outline"] = 0xf1932, + ["md-coffee_maker_outline"] = 0xf181b, + ["md-coffee_off"] = 0xf0faa, + ["md-coffee_off_outline"] = 0xf0fab, + ["md-coffee_outline"] = 0xf06ca, + ["md-coffee_to_go"] = 0xf0177, + ["md-coffee_to_go_outline"] = 0xf130e, + ["md-coffin"] = 0xf0b7f, + ["md-cog"] = 0xf0493, + ["md-cog_box"] = 0xf0494, + ["md-cog_clockwise"] = 0xf11dd, + ["md-cog_counterclockwise"] = 0xf11de, + ["md-cog_off"] = 0xf13ce, + ["md-cog_off_outline"] = 0xf13cf, + ["md-cog_outline"] = 0xf08bb, + ["md-cog_pause"] = 0xf1933, + ["md-cog_pause_outline"] = 0xf1934, + ["md-cog_play"] = 0xf1935, + ["md-cog_play_outline"] = 0xf1936, + ["md-cog_refresh"] = 0xf145e, + ["md-cog_refresh_outline"] = 0xf145f, + ["md-cog_stop"] = 0xf1937, + ["md-cog_stop_outline"] = 0xf1938, + ["md-cog_sync"] = 0xf1460, + ["md-cog_sync_outline"] = 0xf1461, + ["md-cog_transfer"] = 0xf105b, + ["md-cog_transfer_outline"] = 0xf105c, + ["md-cogs"] = 0xf08d6, + ["md-collage"] = 0xf0640, + ["md-collapse_all"] = 0xf0aa6, + ["md-collapse_all_outline"] = 0xf0aa7, + ["md-color_helper"] = 0xf0179, + ["md-comma"] = 0xf0e23, + ["md-comma_box"] = 0xf0e2b, + ["md-comma_box_outline"] = 0xf0e24, + ["md-comma_circle"] = 0xf0e25, + ["md-comma_circle_outline"] = 0xf0e26, + ["md-comment"] = 0xf017a, + ["md-comment_account"] = 0xf017b, + ["md-comment_account_outline"] = 0xf017c, + ["md-comment_alert"] = 0xf017d, + ["md-comment_alert_outline"] = 0xf017e, + ["md-comment_arrow_left"] = 0xf09e1, + ["md-comment_arrow_left_outline"] = 0xf09e2, + ["md-comment_arrow_right"] = 0xf09e3, + ["md-comment_arrow_right_outline"] = 0xf09e4, + ["md-comment_bookmark"] = 0xf15ae, + ["md-comment_bookmark_outline"] = 0xf15af, + ["md-comment_check"] = 0xf017f, + ["md-comment_check_outline"] = 0xf0180, + ["md-comment_edit"] = 0xf11bf, + ["md-comment_edit_outline"] = 0xf12c4, + ["md-comment_eye"] = 0xf0a3a, + ["md-comment_eye_outline"] = 0xf0a3b, + ["md-comment_flash"] = 0xf15b0, + ["md-comment_flash_outline"] = 0xf15b1, + ["md-comment_minus"] = 0xf15df, + ["md-comment_minus_outline"] = 0xf15e0, + ["md-comment_multiple"] = 0xf085f, + ["md-comment_multiple_outline"] = 0xf0181, + ["md-comment_off"] = 0xf15e1, + ["md-comment_off_outline"] = 0xf15e2, + ["md-comment_outline"] = 0xf0182, + ["md-comment_plus"] = 0xf09e5, + ["md-comment_plus_outline"] = 0xf0183, + ["md-comment_processing"] = 0xf0184, + ["md-comment_processing_outline"] = 0xf0185, + ["md-comment_question"] = 0xf0817, + ["md-comment_question_outline"] = 0xf0186, + ["md-comment_quote"] = 0xf1021, + ["md-comment_quote_outline"] = 0xf1022, + ["md-comment_remove"] = 0xf05de, + ["md-comment_remove_outline"] = 0xf0187, + ["md-comment_search"] = 0xf0a3c, + ["md-comment_search_outline"] = 0xf0a3d, + ["md-comment_text"] = 0xf0188, + ["md-comment_text_multiple"] = 0xf0860, + ["md-comment_text_multiple_outline"] = 0xf0861, + ["md-comment_text_outline"] = 0xf0189, + ["md-compare"] = 0xf018a, + ["md-compare_horizontal"] = 0xf1492, + ["md-compare_remove"] = 0xf18b3, + ["md-compare_vertical"] = 0xf1493, + ["md-compass"] = 0xf018b, + ["md-compass_off"] = 0xf0b80, + ["md-compass_off_outline"] = 0xf0b81, + ["md-compass_outline"] = 0xf018c, + ["md-compass_rose"] = 0xf1382, + ["md-compost"] = 0xf1a38, + ["md-cone"] = 0xf194c, + ["md-cone_off"] = 0xf194d, + ["md-connection"] = 0xf1616, + ["md-console"] = 0xf018d, + ["md-console_line"] = 0xf07b7, + ["md-console_network"] = 0xf08a9, + ["md-console_network_outline"] = 0xf0c60, + ["md-consolidate"] = 0xf10d8, + ["md-contactless_payment"] = 0xf0d6a, + ["md-contactless_payment_circle"] = 0xf0321, + ["md-contactless_payment_circle_outline"] = 0xf0408, + ["md-contacts"] = 0xf06cb, + ["md-contacts_outline"] = 0xf05b8, + ["md-contain"] = 0xf0a3e, + ["md-contain_end"] = 0xf0a3f, + ["md-contain_start"] = 0xf0a40, + ["md-content_copy"] = 0xf018f, + ["md-content_cut"] = 0xf0190, + ["md-content_duplicate"] = 0xf0191, + ["md-content_paste"] = 0xf0192, + ["md-content_save"] = 0xf0193, + ["md-content_save_alert"] = 0xf0f42, + ["md-content_save_alert_outline"] = 0xf0f43, + ["md-content_save_all"] = 0xf0194, + ["md-content_save_all_outline"] = 0xf0f44, + ["md-content_save_check"] = 0xf18ea, + ["md-content_save_check_outline"] = 0xf18eb, + ["md-content_save_cog"] = 0xf145b, + ["md-content_save_cog_outline"] = 0xf145c, + ["md-content_save_edit"] = 0xf0cfb, + ["md-content_save_edit_outline"] = 0xf0cfc, + ["md-content_save_move"] = 0xf0e27, + ["md-content_save_move_outline"] = 0xf0e28, + ["md-content_save_off"] = 0xf1643, + ["md-content_save_off_outline"] = 0xf1644, + ["md-content_save_outline"] = 0xf0818, + ["md-content_save_settings"] = 0xf061b, + ["md-content_save_settings_outline"] = 0xf0b2e, + ["md-contrast"] = 0xf0195, + ["md-contrast_box"] = 0xf0196, + ["md-contrast_circle"] = 0xf0197, + ["md-controller_classic"] = 0xf0b82, + ["md-controller_classic_outline"] = 0xf0b83, + ["md-cookie"] = 0xf0198, + ["md-cookie_alert"] = 0xf16d0, + ["md-cookie_alert_outline"] = 0xf16d1, + ["md-cookie_check"] = 0xf16d2, + ["md-cookie_check_outline"] = 0xf16d3, + ["md-cookie_clock"] = 0xf16e4, + ["md-cookie_clock_outline"] = 0xf16e5, + ["md-cookie_cog"] = 0xf16d4, + ["md-cookie_cog_outline"] = 0xf16d5, + ["md-cookie_edit"] = 0xf16e6, + ["md-cookie_edit_outline"] = 0xf16e7, + ["md-cookie_lock"] = 0xf16e8, + ["md-cookie_lock_outline"] = 0xf16e9, + ["md-cookie_minus"] = 0xf16da, + ["md-cookie_minus_outline"] = 0xf16db, + ["md-cookie_off"] = 0xf16ea, + ["md-cookie_off_outline"] = 0xf16eb, + ["md-cookie_outline"] = 0xf16de, + ["md-cookie_plus"] = 0xf16d6, + ["md-cookie_plus_outline"] = 0xf16d7, + ["md-cookie_refresh"] = 0xf16ec, + ["md-cookie_refresh_outline"] = 0xf16ed, + ["md-cookie_remove"] = 0xf16d8, + ["md-cookie_remove_outline"] = 0xf16d9, + ["md-cookie_settings"] = 0xf16dc, + ["md-cookie_settings_outline"] = 0xf16dd, + ["md-coolant_temperature"] = 0xf03c8, + ["md-copyleft"] = 0xf1939, + ["md-copyright"] = 0xf05e6, + ["md-cordova"] = 0xf0958, + ["md-corn"] = 0xf07b8, + ["md-corn_off"] = 0xf13ef, + ["md-cosine_wave"] = 0xf1479, + ["md-counter"] = 0xf0199, + ["md-countertop"] = 0xf181c, + ["md-countertop_outline"] = 0xf181d, + ["md-cow"] = 0xf019a, + ["md-cow_off"] = 0xf18fc, + ["md-cpu_32_bit"] = 0xf0edf, + ["md-cpu_64_bit"] = 0xf0ee0, + ["md-cradle"] = 0xf198b, + ["md-cradle_outline"] = 0xf1991, + ["md-crane"] = 0xf0862, + ["md-creation"] = 0xf0674, + ["md-creative_commons"] = 0xf0d6b, + ["md-credit_card"] = 0xf0fef, + ["md-credit_card_check"] = 0xf13d0, + ["md-credit_card_check_outline"] = 0xf13d1, + ["md-credit_card_chip"] = 0xf190f, + ["md-credit_card_chip_outline"] = 0xf1910, + ["md-credit_card_clock"] = 0xf0ee1, + ["md-credit_card_clock_outline"] = 0xf0ee2, + ["md-credit_card_edit"] = 0xf17d7, + ["md-credit_card_edit_outline"] = 0xf17d8, + ["md-credit_card_fast"] = 0xf1911, + ["md-credit_card_fast_outline"] = 0xf1912, + ["md-credit_card_lock"] = 0xf18e7, + ["md-credit_card_lock_outline"] = 0xf18e8, + ["md-credit_card_marker"] = 0xf06a8, + ["md-credit_card_marker_outline"] = 0xf0dbe, + ["md-credit_card_minus"] = 0xf0fac, + ["md-credit_card_minus_outline"] = 0xf0fad, + ["md-credit_card_multiple"] = 0xf0ff0, + ["md-credit_card_multiple_outline"] = 0xf019c, + ["md-credit_card_off"] = 0xf0ff1, + ["md-credit_card_off_outline"] = 0xf05e4, + ["md-credit_card_outline"] = 0xf019b, + ["md-credit_card_plus"] = 0xf0ff2, + ["md-credit_card_plus_outline"] = 0xf0676, + ["md-credit_card_refresh"] = 0xf1645, + ["md-credit_card_refresh_outline"] = 0xf1646, + ["md-credit_card_refund"] = 0xf0ff3, + ["md-credit_card_refund_outline"] = 0xf0aa8, + ["md-credit_card_remove"] = 0xf0fae, + ["md-credit_card_remove_outline"] = 0xf0faf, + ["md-credit_card_scan"] = 0xf0ff4, + ["md-credit_card_scan_outline"] = 0xf019d, + ["md-credit_card_search"] = 0xf1647, + ["md-credit_card_search_outline"] = 0xf1648, + ["md-credit_card_settings"] = 0xf0ff5, + ["md-credit_card_settings_outline"] = 0xf08d7, + ["md-credit_card_sync"] = 0xf1649, + ["md-credit_card_sync_outline"] = 0xf164a, + ["md-credit_card_wireless"] = 0xf0802, + ["md-credit_card_wireless_off"] = 0xf057a, + ["md-credit_card_wireless_off_outline"] = 0xf057b, + ["md-credit_card_wireless_outline"] = 0xf0d6c, + ["md-cricket"] = 0xf0d6d, + ["md-crop"] = 0xf019e, + ["md-crop_free"] = 0xf019f, + ["md-crop_landscape"] = 0xf01a0, + ["md-crop_portrait"] = 0xf01a1, + ["md-crop_rotate"] = 0xf0696, + ["md-crop_square"] = 0xf01a2, + ["md-cross"] = 0xf0953, + ["md-cross_bolnisi"] = 0xf0ced, + ["md-cross_celtic"] = 0xf0cf5, + ["md-cross_outline"] = 0xf0cf6, + ["md-crosshairs"] = 0xf01a3, + ["md-crosshairs_gps"] = 0xf01a4, + ["md-crosshairs_off"] = 0xf0f45, + ["md-crosshairs_question"] = 0xf1136, + ["md-crowd"] = 0xf1975, + ["md-crown"] = 0xf01a5, + ["md-crown_circle"] = 0xf17dc, + ["md-crown_circle_outline"] = 0xf17dd, + ["md-crown_outline"] = 0xf11d0, + ["md-cryengine"] = 0xf0959, + ["md-crystal_ball"] = 0xf0b2f, + ["md-cube"] = 0xf01a6, + ["md-cube_off"] = 0xf141c, + ["md-cube_off_outline"] = 0xf141d, + ["md-cube_outline"] = 0xf01a7, + ["md-cube_scan"] = 0xf0b84, + ["md-cube_send"] = 0xf01a8, + ["md-cube_unfolded"] = 0xf01a9, + ["md-cup"] = 0xf01aa, + ["md-cup_off"] = 0xf05e5, + ["md-cup_off_outline"] = 0xf137d, + ["md-cup_outline"] = 0xf130f, + ["md-cup_water"] = 0xf01ab, + ["md-cupboard"] = 0xf0f46, + ["md-cupboard_outline"] = 0xf0f47, + ["md-cupcake"] = 0xf095a, + ["md-curling"] = 0xf0863, + ["md-currency_bdt"] = 0xf0864, + ["md-currency_brl"] = 0xf0b85, + ["md-currency_btc"] = 0xf01ac, + ["md-currency_cny"] = 0xf07ba, + ["md-currency_eth"] = 0xf07bb, + ["md-currency_eur"] = 0xf01ad, + ["md-currency_eur_off"] = 0xf1315, + ["md-currency_fra"] = 0xf1a39, + ["md-currency_gbp"] = 0xf01ae, + ["md-currency_ils"] = 0xf0c61, + ["md-currency_inr"] = 0xf01af, + ["md-currency_jpy"] = 0xf07bc, + ["md-currency_krw"] = 0xf07bd, + ["md-currency_kzt"] = 0xf0865, + ["md-currency_mnt"] = 0xf1512, + ["md-currency_ngn"] = 0xf01b0, + ["md-currency_php"] = 0xf09e6, + ["md-currency_rial"] = 0xf0e9c, + ["md-currency_rub"] = 0xf01b1, + ["md-currency_rupee"] = 0xf1976, + ["md-currency_sign"] = 0xf07be, + ["md-currency_try"] = 0xf01b2, + ["md-currency_twd"] = 0xf07bf, + ["md-currency_usd"] = 0xf01c1, + ["md-currency_usd_off"] = 0xf067a, + ["md-current_ac"] = 0xf1480, + ["md-current_dc"] = 0xf095c, + ["md-cursor_default"] = 0xf01c0, + ["md-cursor_default_click"] = 0xf0cfd, + ["md-cursor_default_click_outline"] = 0xf0cfe, + ["md-cursor_default_gesture"] = 0xf1127, + ["md-cursor_default_gesture_outline"] = 0xf1128, + ["md-cursor_default_outline"] = 0xf01bf, + ["md-cursor_move"] = 0xf01be, + ["md-cursor_pointer"] = 0xf01bd, + ["md-cursor_text"] = 0xf05e7, + ["md-curtains"] = 0xf1846, + ["md-curtains_closed"] = 0xf1847, + ["md-cylinder"] = 0xf194e, + ["md-cylinder_off"] = 0xf194f, + ["md-dance_ballroom"] = 0xf15fb, + ["md-dance_pole"] = 0xf1578, + ["md-data_matrix"] = 0xf153c, + ["md-data_matrix_edit"] = 0xf153d, + ["md-data_matrix_minus"] = 0xf153e, + ["md-data_matrix_plus"] = 0xf153f, + ["md-data_matrix_remove"] = 0xf1540, + ["md-data_matrix_scan"] = 0xf1541, + ["md-database"] = 0xf01bc, + ["md-database_alert"] = 0xf163a, + ["md-database_alert_outline"] = 0xf1624, + ["md-database_arrow_down"] = 0xf163b, + ["md-database_arrow_down_outline"] = 0xf1625, + ["md-database_arrow_left"] = 0xf163c, + ["md-database_arrow_left_outline"] = 0xf1626, + ["md-database_arrow_right"] = 0xf163d, + ["md-database_arrow_right_outline"] = 0xf1627, + ["md-database_arrow_up"] = 0xf163e, + ["md-database_arrow_up_outline"] = 0xf1628, + ["md-database_check"] = 0xf0aa9, + ["md-database_check_outline"] = 0xf1629, + ["md-database_clock"] = 0xf163f, + ["md-database_clock_outline"] = 0xf162a, + ["md-database_cog"] = 0xf164b, + ["md-database_cog_outline"] = 0xf164c, + ["md-database_edit"] = 0xf0b86, + ["md-database_edit_outline"] = 0xf162b, + ["md-database_export"] = 0xf095e, + ["md-database_export_outline"] = 0xf162c, + ["md-database_eye"] = 0xf191f, + ["md-database_eye_off"] = 0xf1920, + ["md-database_eye_off_outline"] = 0xf1921, + ["md-database_eye_outline"] = 0xf1922, + ["md-database_import"] = 0xf095d, + ["md-database_import_outline"] = 0xf162d, + ["md-database_lock"] = 0xf0aaa, + ["md-database_lock_outline"] = 0xf162e, + ["md-database_marker"] = 0xf12f6, + ["md-database_marker_outline"] = 0xf162f, + ["md-database_minus"] = 0xf01bb, + ["md-database_minus_outline"] = 0xf1630, + ["md-database_off"] = 0xf1640, + ["md-database_off_outline"] = 0xf1631, + ["md-database_outline"] = 0xf1632, + ["md-database_plus"] = 0xf01ba, + ["md-database_plus_outline"] = 0xf1633, + ["md-database_refresh"] = 0xf05c2, + ["md-database_refresh_outline"] = 0xf1634, + ["md-database_remove"] = 0xf0d00, + ["md-database_remove_outline"] = 0xf1635, + ["md-database_search"] = 0xf0866, + ["md-database_search_outline"] = 0xf1636, + ["md-database_settings"] = 0xf0d01, + ["md-database_settings_outline"] = 0xf1637, + ["md-database_sync"] = 0xf0cff, + ["md-database_sync_outline"] = 0xf1638, + ["md-death_star"] = 0xf08d8, + ["md-death_star_variant"] = 0xf08d9, + ["md-deathly_hallows"] = 0xf0b87, + ["md-debian"] = 0xf08da, + ["md-debug_step_into"] = 0xf01b9, + ["md-debug_step_out"] = 0xf01b8, + ["md-debug_step_over"] = 0xf01b7, + ["md-decagram"] = 0xf076c, + ["md-decagram_outline"] = 0xf076d, + ["md-decimal"] = 0xf10a1, + ["md-decimal_comma"] = 0xf10a2, + ["md-decimal_comma_decrease"] = 0xf10a3, + ["md-decimal_comma_increase"] = 0xf10a4, + ["md-decimal_decrease"] = 0xf01b6, + ["md-decimal_increase"] = 0xf01b5, + ["md-delete"] = 0xf01b4, + ["md-delete_alert"] = 0xf10a5, + ["md-delete_alert_outline"] = 0xf10a6, + ["md-delete_circle"] = 0xf0683, + ["md-delete_circle_outline"] = 0xf0b88, + ["md-delete_clock"] = 0xf1556, + ["md-delete_clock_outline"] = 0xf1557, + ["md-delete_empty"] = 0xf06cc, + ["md-delete_empty_outline"] = 0xf0e9d, + ["md-delete_forever"] = 0xf05e8, + ["md-delete_forever_outline"] = 0xf0b89, + ["md-delete_off"] = 0xf10a7, + ["md-delete_off_outline"] = 0xf10a8, + ["md-delete_outline"] = 0xf09e7, + ["md-delete_restore"] = 0xf0819, + ["md-delete_sweep"] = 0xf05e9, + ["md-delete_sweep_outline"] = 0xf0c62, + ["md-delete_variant"] = 0xf01b3, + ["md-delta"] = 0xf01c2, + ["md-desk"] = 0xf1239, + ["md-desk_lamp"] = 0xf095f, + ["md-deskphone"] = 0xf01c3, + ["md-desktop_classic"] = 0xf07c0, + ["md-desktop_mac"] = 0xf01c4, + ["md-desktop_mac_dashboard"] = 0xf09e8, + ["md-desktop_tower"] = 0xf01c5, + ["md-desktop_tower_monitor"] = 0xf0aab, + ["md-details"] = 0xf01c6, + ["md-dev_to"] = 0xf0d6e, + ["md-developer_board"] = 0xf0697, + ["md-deviantart"] = 0xf01c7, + ["md-devices"] = 0xf0fb0, + ["md-dharmachakra"] = 0xf094b, + ["md-diabetes"] = 0xf1126, + ["md-dialpad"] = 0xf061c, + ["md-diameter"] = 0xf0c63, + ["md-diameter_outline"] = 0xf0c64, + ["md-diameter_variant"] = 0xf0c65, + ["md-diamond"] = 0xf0b8a, + ["md-diamond_outline"] = 0xf0b8b, + ["md-diamond_stone"] = 0xf01c8, + ["md-dice_1"] = 0xf01ca, + ["md-dice_1_outline"] = 0xf114a, + ["md-dice_2"] = 0xf01cb, + ["md-dice_2_outline"] = 0xf114b, + ["md-dice_3"] = 0xf01cc, + ["md-dice_3_outline"] = 0xf114c, + ["md-dice_4"] = 0xf01cd, + ["md-dice_4_outline"] = 0xf114d, + ["md-dice_5"] = 0xf01ce, + ["md-dice_5_outline"] = 0xf114e, + ["md-dice_6"] = 0xf01cf, + ["md-dice_6_outline"] = 0xf114f, + ["md-dice_d10"] = 0xf1153, + ["md-dice_d10_outline"] = 0xf076f, + ["md-dice_d12"] = 0xf1154, + ["md-dice_d12_outline"] = 0xf0867, + ["md-dice_d20"] = 0xf1155, + ["md-dice_d20_outline"] = 0xf05ea, + ["md-dice_d4"] = 0xf1150, + ["md-dice_d4_outline"] = 0xf05eb, + ["md-dice_d6"] = 0xf1151, + ["md-dice_d6_outline"] = 0xf05ed, + ["md-dice_d8"] = 0xf1152, + ["md-dice_d8_outline"] = 0xf05ec, + ["md-dice_multiple"] = 0xf076e, + ["md-dice_multiple_outline"] = 0xf1156, + ["md-digital_ocean"] = 0xf1237, + ["md-dip_switch"] = 0xf07c1, + ["md-directions"] = 0xf01d0, + ["md-directions_fork"] = 0xf0641, + ["md-disc"] = 0xf05ee, + ["md-disc_alert"] = 0xf01d1, + ["md-disc_player"] = 0xf0960, + ["md-discord"] = 0xf066f, + ["md-dishwasher"] = 0xf0aac, + ["md-dishwasher_alert"] = 0xf11b8, + ["md-dishwasher_off"] = 0xf11b9, + ["md-disqus"] = 0xf01d2, + ["md-distribute_horizontal_center"] = 0xf11c9, + ["md-distribute_horizontal_left"] = 0xf11c8, + ["md-distribute_horizontal_right"] = 0xf11ca, + ["md-distribute_vertical_bottom"] = 0xf11cb, + ["md-distribute_vertical_center"] = 0xf11cc, + ["md-distribute_vertical_top"] = 0xf11cd, + ["md-diversify"] = 0xf1877, + ["md-diving"] = 0xf1977, + ["md-diving_flippers"] = 0xf0dbf, + ["md-diving_helmet"] = 0xf0dc0, + ["md-diving_scuba"] = 0xf0dc1, + ["md-diving_scuba_flag"] = 0xf0dc2, + ["md-diving_scuba_tank"] = 0xf0dc3, + ["md-diving_scuba_tank_multiple"] = 0xf0dc4, + ["md-diving_snorkel"] = 0xf0dc5, + ["md-division"] = 0xf01d4, + ["md-division_box"] = 0xf01d5, + ["md-dlna"] = 0xf0a41, + ["md-dna"] = 0xf0684, + ["md-dns"] = 0xf01d6, + ["md-dns_outline"] = 0xf0b8c, + ["md-dock_bottom"] = 0xf10a9, + ["md-dock_left"] = 0xf10aa, + ["md-dock_right"] = 0xf10ab, + ["md-dock_top"] = 0xf1513, + ["md-dock_window"] = 0xf10ac, + ["md-docker"] = 0xf0868, + ["md-doctor"] = 0xf0a42, + ["md-dog"] = 0xf0a43, + ["md-dog_service"] = 0xf0aad, + ["md-dog_side"] = 0xf0a44, + ["md-dog_side_off"] = 0xf16ee, + ["md-dolby"] = 0xf06b3, + ["md-dolly"] = 0xf0e9e, + ["md-dolphin"] = 0xf18b4, + ["md-domain"] = 0xf01d7, + ["md-domain_off"] = 0xf0d6f, + ["md-domain_plus"] = 0xf10ad, + ["md-domain_remove"] = 0xf10ae, + ["md-dome_light"] = 0xf141e, + ["md-domino_mask"] = 0xf1023, + ["md-donkey"] = 0xf07c2, + ["md-door"] = 0xf081a, + ["md-door_closed"] = 0xf081b, + ["md-door_closed_lock"] = 0xf10af, + ["md-door_open"] = 0xf081c, + ["md-door_sliding"] = 0xf181e, + ["md-door_sliding_lock"] = 0xf181f, + ["md-door_sliding_open"] = 0xf1820, + ["md-doorbell"] = 0xf12e6, + ["md-doorbell_video"] = 0xf0869, + ["md-dot_net"] = 0xf0aae, + ["md-dots_circle"] = 0xf1978, + ["md-dots_grid"] = 0xf15fc, + ["md-dots_hexagon"] = 0xf15ff, + ["md-dots_horizontal"] = 0xf01d8, + ["md-dots_horizontal_circle"] = 0xf07c3, + ["md-dots_horizontal_circle_outline"] = 0xf0b8d, + ["md-dots_square"] = 0xf15fd, + ["md-dots_triangle"] = 0xf15fe, + ["md-dots_vertical"] = 0xf01d9, + ["md-dots_vertical_circle"] = 0xf07c4, + ["md-dots_vertical_circle_outline"] = 0xf0b8e, + ["md-download"] = 0xf01da, + ["md-download_box"] = 0xf1462, + ["md-download_box_outline"] = 0xf1463, + ["md-download_circle"] = 0xf1464, + ["md-download_circle_outline"] = 0xf1465, + ["md-download_lock"] = 0xf1320, + ["md-download_lock_outline"] = 0xf1321, + ["md-download_multiple"] = 0xf09e9, + ["md-download_network"] = 0xf06f4, + ["md-download_network_outline"] = 0xf0c66, + ["md-download_off"] = 0xf10b0, + ["md-download_off_outline"] = 0xf10b1, + ["md-download_outline"] = 0xf0b8f, + ["md-drag"] = 0xf01db, + ["md-drag_horizontal"] = 0xf01dc, + ["md-drag_horizontal_variant"] = 0xf12f0, + ["md-drag_variant"] = 0xf0b90, + ["md-drag_vertical"] = 0xf01dd, + ["md-drag_vertical_variant"] = 0xf12f1, + ["md-drama_masks"] = 0xf0d02, + ["md-draw"] = 0xf0f49, + ["md-draw_pen"] = 0xf19b9, + ["md-drawing"] = 0xf01de, + ["md-drawing_box"] = 0xf01df, + ["md-dresser"] = 0xf0f4a, + ["md-dresser_outline"] = 0xf0f4b, + ["md-drone"] = 0xf01e2, + ["md-dropbox"] = 0xf01e3, + ["md-drupal"] = 0xf01e4, + ["md-duck"] = 0xf01e5, + ["md-dumbbell"] = 0xf01e6, + ["md-dump_truck"] = 0xf0c67, + ["md-ear_hearing"] = 0xf07c5, + ["md-ear_hearing_loop"] = 0xf1aee, + ["md-ear_hearing_off"] = 0xf0a45, + ["md-earbuds"] = 0xf184f, + ["md-earbuds_off"] = 0xf1850, + ["md-earbuds_off_outline"] = 0xf1851, + ["md-earbuds_outline"] = 0xf1852, + ["md-earth"] = 0xf01e7, + ["md-earth_arrow_right"] = 0xf1311, + ["md-earth_box"] = 0xf06cd, + ["md-earth_box_minus"] = 0xf1407, + ["md-earth_box_off"] = 0xf06ce, + ["md-earth_box_plus"] = 0xf1406, + ["md-earth_box_remove"] = 0xf1408, + ["md-earth_minus"] = 0xf1404, + ["md-earth_off"] = 0xf01e8, + ["md-earth_plus"] = 0xf1403, + ["md-earth_remove"] = 0xf1405, + ["md-egg"] = 0xf0aaf, + ["md-egg_easter"] = 0xf0ab0, + ["md-egg_fried"] = 0xf184a, + ["md-egg_off"] = 0xf13f0, + ["md-egg_off_outline"] = 0xf13f1, + ["md-egg_outline"] = 0xf13f2, + ["md-eiffel_tower"] = 0xf156b, + ["md-eight_track"] = 0xf09ea, + ["md-eject"] = 0xf01ea, + ["md-eject_outline"] = 0xf0b91, + ["md-electric_switch"] = 0xf0e9f, + ["md-electric_switch_closed"] = 0xf10d9, + ["md-electron_framework"] = 0xf1024, + ["md-elephant"] = 0xf07c6, + ["md-elevation_decline"] = 0xf01eb, + ["md-elevation_rise"] = 0xf01ec, + ["md-elevator"] = 0xf01ed, + ["md-elevator_down"] = 0xf12c2, + ["md-elevator_passenger"] = 0xf1381, + ["md-elevator_passenger_off"] = 0xf1979, + ["md-elevator_passenger_off_outline"] = 0xf197a, + ["md-elevator_passenger_outline"] = 0xf197b, + ["md-elevator_up"] = 0xf12c1, + ["md-ellipse"] = 0xf0ea0, + ["md-ellipse_outline"] = 0xf0ea1, + ["md-email"] = 0xf01ee, + ["md-email_alert"] = 0xf06cf, + ["md-email_alert_outline"] = 0xf0d42, + ["md-email_box"] = 0xf0d03, + ["md-email_check"] = 0xf0ab1, + ["md-email_check_outline"] = 0xf0ab2, + ["md-email_edit"] = 0xf0ee3, + ["md-email_edit_outline"] = 0xf0ee4, + ["md-email_fast"] = 0xf186f, + ["md-email_fast_outline"] = 0xf1870, + ["md-email_lock"] = 0xf01f1, + ["md-email_mark_as_unread"] = 0xf0b92, + ["md-email_minus"] = 0xf0ee5, + ["md-email_minus_outline"] = 0xf0ee6, + ["md-email_multiple"] = 0xf0ee7, + ["md-email_multiple_outline"] = 0xf0ee8, + ["md-email_newsletter"] = 0xf0fb1, + ["md-email_off"] = 0xf13e3, + ["md-email_off_outline"] = 0xf13e4, + ["md-email_open"] = 0xf01ef, + ["md-email_open_multiple"] = 0xf0ee9, + ["md-email_open_multiple_outline"] = 0xf0eea, + ["md-email_open_outline"] = 0xf05ef, + ["md-email_outline"] = 0xf01f0, + ["md-email_plus"] = 0xf09eb, + ["md-email_plus_outline"] = 0xf09ec, + ["md-email_receive"] = 0xf10da, + ["md-email_receive_outline"] = 0xf10db, + ["md-email_remove"] = 0xf1661, + ["md-email_remove_outline"] = 0xf1662, + ["md-email_seal"] = 0xf195b, + ["md-email_seal_outline"] = 0xf195c, + ["md-email_search"] = 0xf0961, + ["md-email_search_outline"] = 0xf0962, + ["md-email_send"] = 0xf10dc, + ["md-email_send_outline"] = 0xf10dd, + ["md-email_sync"] = 0xf12c7, + ["md-email_sync_outline"] = 0xf12c8, + ["md-email_variant"] = 0xf05f0, + ["md-ember"] = 0xf0b30, + ["md-emby"] = 0xf06b4, + ["md-emoticon"] = 0xf0c68, + ["md-emoticon_angry"] = 0xf0c69, + ["md-emoticon_angry_outline"] = 0xf0c6a, + ["md-emoticon_confused"] = 0xf10de, + ["md-emoticon_confused_outline"] = 0xf10df, + ["md-emoticon_cool"] = 0xf0c6b, + ["md-emoticon_cool_outline"] = 0xf01f3, + ["md-emoticon_cry"] = 0xf0c6c, + ["md-emoticon_cry_outline"] = 0xf0c6d, + ["md-emoticon_dead"] = 0xf0c6e, + ["md-emoticon_dead_outline"] = 0xf069b, + ["md-emoticon_devil"] = 0xf0c6f, + ["md-emoticon_devil_outline"] = 0xf01f4, + ["md-emoticon_excited"] = 0xf0c70, + ["md-emoticon_excited_outline"] = 0xf069c, + ["md-emoticon_frown"] = 0xf0f4c, + ["md-emoticon_frown_outline"] = 0xf0f4d, + ["md-emoticon_happy"] = 0xf0c71, + ["md-emoticon_happy_outline"] = 0xf01f5, + ["md-emoticon_kiss"] = 0xf0c72, + ["md-emoticon_kiss_outline"] = 0xf0c73, + ["md-emoticon_lol"] = 0xf1214, + ["md-emoticon_lol_outline"] = 0xf1215, + ["md-emoticon_neutral"] = 0xf0c74, + ["md-emoticon_neutral_outline"] = 0xf01f6, + ["md-emoticon_outline"] = 0xf01f2, + ["md-emoticon_poop"] = 0xf01f7, + ["md-emoticon_poop_outline"] = 0xf0c75, + ["md-emoticon_sad"] = 0xf0c76, + ["md-emoticon_sad_outline"] = 0xf01f8, + ["md-emoticon_sick"] = 0xf157c, + ["md-emoticon_sick_outline"] = 0xf157d, + ["md-emoticon_tongue"] = 0xf01f9, + ["md-emoticon_tongue_outline"] = 0xf0c77, + ["md-emoticon_wink"] = 0xf0c78, + ["md-emoticon_wink_outline"] = 0xf0c79, + ["md-engine"] = 0xf01fa, + ["md-engine_off"] = 0xf0a46, + ["md-engine_off_outline"] = 0xf0a47, + ["md-engine_outline"] = 0xf01fb, + ["md-epsilon"] = 0xf10e0, + ["md-equal"] = 0xf01fc, + ["md-equal_box"] = 0xf01fd, + ["md-equalizer"] = 0xf0ea2, + ["md-equalizer_outline"] = 0xf0ea3, + ["md-eraser"] = 0xf01fe, + ["md-eraser_variant"] = 0xf0642, + ["md-escalator"] = 0xf01ff, + ["md-escalator_box"] = 0xf1399, + ["md-escalator_down"] = 0xf12c0, + ["md-escalator_up"] = 0xf12bf, + ["md-eslint"] = 0xf0c7a, + ["md-et"] = 0xf0ab3, + ["md-ethereum"] = 0xf086a, + ["md-ethernet"] = 0xf0200, + ["md-ethernet_cable"] = 0xf0201, + ["md-ethernet_cable_off"] = 0xf0202, + ["md-ev_plug_ccs1"] = 0xf1519, + ["md-ev_plug_ccs2"] = 0xf151a, + ["md-ev_plug_chademo"] = 0xf151b, + ["md-ev_plug_tesla"] = 0xf151c, + ["md-ev_plug_type1"] = 0xf151d, + ["md-ev_plug_type2"] = 0xf151e, + ["md-ev_station"] = 0xf05f1, + ["md-evernote"] = 0xf0204, + ["md-excavator"] = 0xf1025, + ["md-exclamation"] = 0xf0205, + ["md-exclamation_thick"] = 0xf1238, + ["md-exit_run"] = 0xf0a48, + ["md-exit_to_app"] = 0xf05fc, + ["md-expand_all"] = 0xf0ab4, + ["md-expand_all_outline"] = 0xf0ab5, + ["md-expansion_card"] = 0xf08ae, + ["md-expansion_card_variant"] = 0xf0fb2, + ["md-exponent"] = 0xf0963, + ["md-exponent_box"] = 0xf0964, + ["md-export"] = 0xf0207, + ["md-export_variant"] = 0xf0b93, + ["md-eye"] = 0xf0208, + ["md-eye_arrow_left"] = 0xf18fd, + ["md-eye_arrow_left_outline"] = 0xf18fe, + ["md-eye_arrow_right"] = 0xf18ff, + ["md-eye_arrow_right_outline"] = 0xf1900, + ["md-eye_check"] = 0xf0d04, + ["md-eye_check_outline"] = 0xf0d05, + ["md-eye_circle"] = 0xf0b94, + ["md-eye_circle_outline"] = 0xf0b95, + ["md-eye_minus"] = 0xf1026, + ["md-eye_minus_outline"] = 0xf1027, + ["md-eye_off"] = 0xf0209, + ["md-eye_off_outline"] = 0xf06d1, + ["md-eye_outline"] = 0xf06d0, + ["md-eye_plus"] = 0xf086b, + ["md-eye_plus_outline"] = 0xf086c, + ["md-eye_refresh"] = 0xf197c, + ["md-eye_refresh_outline"] = 0xf197d, + ["md-eye_remove"] = 0xf15e3, + ["md-eye_remove_outline"] = 0xf15e4, + ["md-eye_settings"] = 0xf086d, + ["md-eye_settings_outline"] = 0xf086e, + ["md-eyedropper"] = 0xf020a, + ["md-eyedropper_minus"] = 0xf13dd, + ["md-eyedropper_off"] = 0xf13df, + ["md-eyedropper_plus"] = 0xf13dc, + ["md-eyedropper_remove"] = 0xf13de, + ["md-eyedropper_variant"] = 0xf020b, + ["md-face_agent"] = 0xf0d70, + ["md-face_man"] = 0xf0643, + ["md-face_man_outline"] = 0xf0b96, + ["md-face_man_profile"] = 0xf0644, + ["md-face_man_shimmer"] = 0xf15cc, + ["md-face_man_shimmer_outline"] = 0xf15cd, + ["md-face_mask"] = 0xf1586, + ["md-face_mask_outline"] = 0xf1587, + ["md-face_recognition"] = 0xf0c7b, + ["md-face_woman"] = 0xf1077, + ["md-face_woman_outline"] = 0xf1078, + ["md-face_woman_profile"] = 0xf1076, + ["md-face_woman_shimmer"] = 0xf15ce, + ["md-face_woman_shimmer_outline"] = 0xf15cf, + ["md-facebook"] = 0xf020c, + ["md-facebook_gaming"] = 0xf07dd, + ["md-facebook_messenger"] = 0xf020e, + ["md-facebook_workplace"] = 0xf0b31, + ["md-factory"] = 0xf020f, + ["md-family_tree"] = 0xf160e, + ["md-fan"] = 0xf0210, + ["md-fan_alert"] = 0xf146c, + ["md-fan_auto"] = 0xf171d, + ["md-fan_chevron_down"] = 0xf146d, + ["md-fan_chevron_up"] = 0xf146e, + ["md-fan_clock"] = 0xf1a3a, + ["md-fan_minus"] = 0xf1470, + ["md-fan_off"] = 0xf081d, + ["md-fan_plus"] = 0xf146f, + ["md-fan_remove"] = 0xf1471, + ["md-fan_speed_1"] = 0xf1472, + ["md-fan_speed_2"] = 0xf1473, + ["md-fan_speed_3"] = 0xf1474, + ["md-fast_forward"] = 0xf0211, + ["md-fast_forward_10"] = 0xf0d71, + ["md-fast_forward_15"] = 0xf193a, + ["md-fast_forward_30"] = 0xf0d06, + ["md-fast_forward_5"] = 0xf11f8, + ["md-fast_forward_60"] = 0xf160b, + ["md-fast_forward_outline"] = 0xf06d2, + ["md-fax"] = 0xf0212, + ["md-feather"] = 0xf06d3, + ["md-feature_search"] = 0xf0a49, + ["md-feature_search_outline"] = 0xf0a4a, + ["md-fedora"] = 0xf08db, + ["md-fence"] = 0xf179a, + ["md-fence_electric"] = 0xf17f6, + ["md-fencing"] = 0xf14c1, + ["md-ferris_wheel"] = 0xf0ea4, + ["md-ferry"] = 0xf0213, + ["md-file"] = 0xf0214, + ["md-file_account"] = 0xf073b, + ["md-file_account_outline"] = 0xf1028, + ["md-file_alert"] = 0xf0a4b, + ["md-file_alert_outline"] = 0xf0a4c, + ["md-file_arrow_left_right"] = 0xf1a93, + ["md-file_arrow_left_right_outline"] = 0xf1a94, + ["md-file_arrow_up_down"] = 0xf1a95, + ["md-file_arrow_up_down_outline"] = 0xf1a96, + ["md-file_cabinet"] = 0xf0ab6, + ["md-file_cad"] = 0xf0eeb, + ["md-file_cad_box"] = 0xf0eec, + ["md-file_cancel"] = 0xf0dc6, + ["md-file_cancel_outline"] = 0xf0dc7, + ["md-file_certificate"] = 0xf1186, + ["md-file_certificate_outline"] = 0xf1187, + ["md-file_chart"] = 0xf0215, + ["md-file_chart_check"] = 0xf19c6, + ["md-file_chart_check_outline"] = 0xf19c7, + ["md-file_chart_outline"] = 0xf1029, + ["md-file_check"] = 0xf0216, + ["md-file_check_outline"] = 0xf0e29, + ["md-file_clock"] = 0xf12e1, + ["md-file_clock_outline"] = 0xf12e2, + ["md-file_cloud"] = 0xf0217, + ["md-file_cloud_outline"] = 0xf102a, + ["md-file_code"] = 0xf022e, + ["md-file_code_outline"] = 0xf102b, + ["md-file_cog"] = 0xf107b, + ["md-file_cog_outline"] = 0xf107c, + ["md-file_compare"] = 0xf08aa, + ["md-file_delimited"] = 0xf0218, + ["md-file_delimited_outline"] = 0xf0ea5, + ["md-file_document"] = 0xf0219, + ["md-file_document_alert"] = 0xf1a97, + ["md-file_document_alert_outline"] = 0xf1a98, + ["md-file_document_check"] = 0xf1a99, + ["md-file_document_check_outline"] = 0xf1a9a, + ["md-file_document_edit"] = 0xf0dc8, + ["md-file_document_edit_outline"] = 0xf0dc9, + ["md-file_document_minus"] = 0xf1a9b, + ["md-file_document_minus_outline"] = 0xf1a9c, + ["md-file_document_multiple"] = 0xf1517, + ["md-file_document_multiple_outline"] = 0xf1518, + ["md-file_document_outline"] = 0xf09ee, + ["md-file_document_plus"] = 0xf1a9d, + ["md-file_document_plus_outline"] = 0xf1a9e, + ["md-file_document_remove"] = 0xf1a9f, + ["md-file_document_remove_outline"] = 0xf1aa0, + ["md-file_download"] = 0xf0965, + ["md-file_download_outline"] = 0xf0966, + ["md-file_edit"] = 0xf11e7, + ["md-file_edit_outline"] = 0xf11e8, + ["md-file_excel"] = 0xf021b, + ["md-file_excel_box"] = 0xf021c, + ["md-file_excel_box_outline"] = 0xf102c, + ["md-file_excel_outline"] = 0xf102d, + ["md-file_export"] = 0xf021d, + ["md-file_export_outline"] = 0xf102e, + ["md-file_eye"] = 0xf0dca, + ["md-file_eye_outline"] = 0xf0dcb, + ["md-file_find"] = 0xf021e, + ["md-file_find_outline"] = 0xf0b97, + ["md-file_gif_box"] = 0xf0d78, + ["md-file_hidden"] = 0xf0613, + ["md-file_image"] = 0xf021f, + ["md-file_image_marker"] = 0xf1772, + ["md-file_image_marker_outline"] = 0xf1773, + ["md-file_image_minus"] = 0xf193b, + ["md-file_image_minus_outline"] = 0xf193c, + ["md-file_image_outline"] = 0xf0eb0, + ["md-file_image_plus"] = 0xf193d, + ["md-file_image_plus_outline"] = 0xf193e, + ["md-file_image_remove"] = 0xf193f, + ["md-file_image_remove_outline"] = 0xf1940, + ["md-file_import"] = 0xf0220, + ["md-file_import_outline"] = 0xf102f, + ["md-file_jpg_box"] = 0xf0225, + ["md-file_key"] = 0xf1184, + ["md-file_key_outline"] = 0xf1185, + ["md-file_link"] = 0xf1177, + ["md-file_link_outline"] = 0xf1178, + ["md-file_lock"] = 0xf0221, + ["md-file_lock_open"] = 0xf19c8, + ["md-file_lock_open_outline"] = 0xf19c9, + ["md-file_lock_outline"] = 0xf1030, + ["md-file_marker"] = 0xf1774, + ["md-file_marker_outline"] = 0xf1775, + ["md-file_minus"] = 0xf1aa1, + ["md-file_minus_outline"] = 0xf1aa2, + ["md-file_move"] = 0xf0ab9, + ["md-file_move_outline"] = 0xf1031, + ["md-file_multiple"] = 0xf0222, + ["md-file_multiple_outline"] = 0xf1032, + ["md-file_music"] = 0xf0223, + ["md-file_music_outline"] = 0xf0e2a, + ["md-file_outline"] = 0xf0224, + ["md-file_pdf_box"] = 0xf0226, + ["md-file_percent"] = 0xf081e, + ["md-file_percent_outline"] = 0xf1033, + ["md-file_phone"] = 0xf1179, + ["md-file_phone_outline"] = 0xf117a, + ["md-file_plus"] = 0xf0752, + ["md-file_plus_outline"] = 0xf0eed, + ["md-file_png_box"] = 0xf0e2d, + ["md-file_powerpoint"] = 0xf0227, + ["md-file_powerpoint_box"] = 0xf0228, + ["md-file_powerpoint_box_outline"] = 0xf1034, + ["md-file_powerpoint_outline"] = 0xf1035, + ["md-file_presentation_box"] = 0xf0229, + ["md-file_question"] = 0xf086f, + ["md-file_question_outline"] = 0xf1036, + ["md-file_refresh"] = 0xf0918, + ["md-file_refresh_outline"] = 0xf0541, + ["md-file_remove"] = 0xf0b98, + ["md-file_remove_outline"] = 0xf1037, + ["md-file_replace"] = 0xf0b32, + ["md-file_replace_outline"] = 0xf0b33, + ["md-file_restore"] = 0xf0670, + ["md-file_restore_outline"] = 0xf1038, + ["md-file_rotate_left"] = 0xf1a3b, + ["md-file_rotate_left_outline"] = 0xf1a3c, + ["md-file_rotate_right"] = 0xf1a3d, + ["md-file_rotate_right_outline"] = 0xf1a3e, + ["md-file_search"] = 0xf0c7c, + ["md-file_search_outline"] = 0xf0c7d, + ["md-file_send"] = 0xf022a, + ["md-file_send_outline"] = 0xf1039, + ["md-file_settings"] = 0xf1079, + ["md-file_settings_outline"] = 0xf107a, + ["md-file_sign"] = 0xf19c3, + ["md-file_star"] = 0xf103a, + ["md-file_star_outline"] = 0xf103b, + ["md-file_swap"] = 0xf0fb4, + ["md-file_swap_outline"] = 0xf0fb5, + ["md-file_sync"] = 0xf1216, + ["md-file_sync_outline"] = 0xf1217, + ["md-file_table"] = 0xf0c7e, + ["md-file_table_box"] = 0xf10e1, + ["md-file_table_box_multiple"] = 0xf10e2, + ["md-file_table_box_multiple_outline"] = 0xf10e3, + ["md-file_table_box_outline"] = 0xf10e4, + ["md-file_table_outline"] = 0xf0c7f, + ["md-file_tree"] = 0xf0645, + ["md-file_tree_outline"] = 0xf13d2, + ["md-file_undo"] = 0xf08dc, + ["md-file_undo_outline"] = 0xf103c, + ["md-file_upload"] = 0xf0a4d, + ["md-file_upload_outline"] = 0xf0a4e, + ["md-file_video"] = 0xf022b, + ["md-file_video_outline"] = 0xf0e2c, + ["md-file_word"] = 0xf022c, + ["md-file_word_box"] = 0xf022d, + ["md-file_word_box_outline"] = 0xf103d, + ["md-file_word_outline"] = 0xf103e, + ["md-film"] = 0xf022f, + ["md-filmstrip"] = 0xf0230, + ["md-filmstrip_box"] = 0xf0332, + ["md-filmstrip_box_multiple"] = 0xf0d18, + ["md-filmstrip_off"] = 0xf0231, + ["md-filter"] = 0xf0232, + ["md-filter_check"] = 0xf18ec, + ["md-filter_check_outline"] = 0xf18ed, + ["md-filter_cog"] = 0xf1aa3, + ["md-filter_cog_outline"] = 0xf1aa4, + ["md-filter_menu"] = 0xf10e5, + ["md-filter_menu_outline"] = 0xf10e6, + ["md-filter_minus"] = 0xf0eee, + ["md-filter_minus_outline"] = 0xf0eef, + ["md-filter_multiple"] = 0xf1a3f, + ["md-filter_multiple_outline"] = 0xf1a40, + ["md-filter_off"] = 0xf14ef, + ["md-filter_off_outline"] = 0xf14f0, + ["md-filter_outline"] = 0xf0233, + ["md-filter_plus"] = 0xf0ef0, + ["md-filter_plus_outline"] = 0xf0ef1, + ["md-filter_remove"] = 0xf0234, + ["md-filter_remove_outline"] = 0xf0235, + ["md-filter_settings"] = 0xf1aa5, + ["md-filter_settings_outline"] = 0xf1aa6, + ["md-filter_variant"] = 0xf0236, + ["md-filter_variant_minus"] = 0xf1112, + ["md-filter_variant_plus"] = 0xf1113, + ["md-filter_variant_remove"] = 0xf103f, + ["md-finance"] = 0xf081f, + ["md-find_replace"] = 0xf06d4, + ["md-fingerprint"] = 0xf0237, + ["md-fingerprint_off"] = 0xf0eb1, + ["md-fire"] = 0xf0238, + ["md-fire_alert"] = 0xf15d7, + ["md-fire_circle"] = 0xf1807, + ["md-fire_extinguisher"] = 0xf0ef2, + ["md-fire_hydrant"] = 0xf1137, + ["md-fire_hydrant_alert"] = 0xf1138, + ["md-fire_hydrant_off"] = 0xf1139, + ["md-fire_off"] = 0xf1722, + ["md-fire_truck"] = 0xf08ab, + ["md-firebase"] = 0xf0967, + ["md-firefox"] = 0xf0239, + ["md-fireplace"] = 0xf0e2e, + ["md-fireplace_off"] = 0xf0e2f, + ["md-firewire"] = 0xf05be, + ["md-firework"] = 0xf0e30, + ["md-firework_off"] = 0xf1723, + ["md-fish"] = 0xf023a, + ["md-fish_off"] = 0xf13f3, + ["md-fishbowl"] = 0xf0ef3, + ["md-fishbowl_outline"] = 0xf0ef4, + ["md-fit_to_page"] = 0xf0ef5, + ["md-fit_to_page_outline"] = 0xf0ef6, + ["md-fit_to_screen"] = 0xf18f4, + ["md-fit_to_screen_outline"] = 0xf18f5, + ["md-flag"] = 0xf023b, + ["md-flag_checkered"] = 0xf023c, + ["md-flag_minus"] = 0xf0b99, + ["md-flag_minus_outline"] = 0xf10b2, + ["md-flag_off"] = 0xf18ee, + ["md-flag_off_outline"] = 0xf18ef, + ["md-flag_outline"] = 0xf023d, + ["md-flag_plus"] = 0xf0b9a, + ["md-flag_plus_outline"] = 0xf10b3, + ["md-flag_remove"] = 0xf0b9b, + ["md-flag_remove_outline"] = 0xf10b4, + ["md-flag_triangle"] = 0xf023f, + ["md-flag_variant"] = 0xf0240, + ["md-flag_variant_outline"] = 0xf023e, + ["md-flare"] = 0xf0d72, + ["md-flash"] = 0xf0241, + ["md-flash_alert"] = 0xf0ef7, + ["md-flash_alert_outline"] = 0xf0ef8, + ["md-flash_auto"] = 0xf0242, + ["md-flash_off"] = 0xf0243, + ["md-flash_outline"] = 0xf06d5, + ["md-flash_red_eye"] = 0xf067b, + ["md-flashlight"] = 0xf0244, + ["md-flashlight_off"] = 0xf0245, + ["md-flask"] = 0xf0093, + ["md-flask_empty"] = 0xf0094, + ["md-flask_empty_minus"] = 0xf123a, + ["md-flask_empty_minus_outline"] = 0xf123b, + ["md-flask_empty_off"] = 0xf13f4, + ["md-flask_empty_off_outline"] = 0xf13f5, + ["md-flask_empty_outline"] = 0xf0095, + ["md-flask_empty_plus"] = 0xf123c, + ["md-flask_empty_plus_outline"] = 0xf123d, + ["md-flask_empty_remove"] = 0xf123e, + ["md-flask_empty_remove_outline"] = 0xf123f, + ["md-flask_minus"] = 0xf1240, + ["md-flask_minus_outline"] = 0xf1241, + ["md-flask_off"] = 0xf13f6, + ["md-flask_off_outline"] = 0xf13f7, + ["md-flask_outline"] = 0xf0096, + ["md-flask_plus"] = 0xf1242, + ["md-flask_plus_outline"] = 0xf1243, + ["md-flask_remove"] = 0xf1244, + ["md-flask_remove_outline"] = 0xf1245, + ["md-flask_round_bottom"] = 0xf124b, + ["md-flask_round_bottom_empty"] = 0xf124c, + ["md-flask_round_bottom_empty_outline"] = 0xf124d, + ["md-flask_round_bottom_outline"] = 0xf124e, + ["md-fleur_de_lis"] = 0xf1303, + ["md-flip_horizontal"] = 0xf10e7, + ["md-flip_to_back"] = 0xf0247, + ["md-flip_to_front"] = 0xf0248, + ["md-flip_vertical"] = 0xf10e8, + ["md-floor_lamp"] = 0xf08dd, + ["md-floor_lamp_dual"] = 0xf1040, + ["md-floor_lamp_dual_outline"] = 0xf17ce, + ["md-floor_lamp_outline"] = 0xf17c8, + ["md-floor_lamp_torchiere"] = 0xf1747, + ["md-floor_lamp_torchiere_outline"] = 0xf17d6, + ["md-floor_lamp_torchiere_variant"] = 0xf1041, + ["md-floor_lamp_torchiere_variant_outline"] = 0xf17cf, + ["md-floor_plan"] = 0xf0821, + ["md-floppy"] = 0xf0249, + ["md-floppy_variant"] = 0xf09ef, + ["md-flower"] = 0xf024a, + ["md-flower_outline"] = 0xf09f0, + ["md-flower_pollen"] = 0xf1885, + ["md-flower_pollen_outline"] = 0xf1886, + ["md-flower_poppy"] = 0xf0d08, + ["md-flower_tulip"] = 0xf09f1, + ["md-flower_tulip_outline"] = 0xf09f2, + ["md-focus_auto"] = 0xf0f4e, + ["md-focus_field"] = 0xf0f4f, + ["md-focus_field_horizontal"] = 0xf0f50, + ["md-focus_field_vertical"] = 0xf0f51, + ["md-folder"] = 0xf024b, + ["md-folder_account"] = 0xf024c, + ["md-folder_account_outline"] = 0xf0b9c, + ["md-folder_alert"] = 0xf0dcc, + ["md-folder_alert_outline"] = 0xf0dcd, + ["md-folder_arrow_down"] = 0xf19e8, + ["md-folder_arrow_down_outline"] = 0xf19e9, + ["md-folder_arrow_left"] = 0xf19ea, + ["md-folder_arrow_left_outline"] = 0xf19eb, + ["md-folder_arrow_left_right"] = 0xf19ec, + ["md-folder_arrow_left_right_outline"] = 0xf19ed, + ["md-folder_arrow_right"] = 0xf19ee, + ["md-folder_arrow_right_outline"] = 0xf19ef, + ["md-folder_arrow_up"] = 0xf19f0, + ["md-folder_arrow_up_down"] = 0xf19f1, + ["md-folder_arrow_up_down_outline"] = 0xf19f2, + ["md-folder_arrow_up_outline"] = 0xf19f3, + ["md-folder_cancel"] = 0xf19f4, + ["md-folder_cancel_outline"] = 0xf19f5, + ["md-folder_check"] = 0xf197e, + ["md-folder_check_outline"] = 0xf197f, + ["md-folder_clock"] = 0xf0aba, + ["md-folder_clock_outline"] = 0xf0abb, + ["md-folder_cog"] = 0xf107f, + ["md-folder_cog_outline"] = 0xf1080, + ["md-folder_download"] = 0xf024d, + ["md-folder_download_outline"] = 0xf10e9, + ["md-folder_edit"] = 0xf08de, + ["md-folder_edit_outline"] = 0xf0dce, + ["md-folder_eye"] = 0xf178a, + ["md-folder_eye_outline"] = 0xf178b, + ["md-folder_file"] = 0xf19f6, + ["md-folder_file_outline"] = 0xf19f7, + ["md-folder_google_drive"] = 0xf024e, + ["md-folder_heart"] = 0xf10ea, + ["md-folder_heart_outline"] = 0xf10eb, + ["md-folder_hidden"] = 0xf179e, + ["md-folder_home"] = 0xf10b5, + ["md-folder_home_outline"] = 0xf10b6, + ["md-folder_image"] = 0xf024f, + ["md-folder_information"] = 0xf10b7, + ["md-folder_information_outline"] = 0xf10b8, + ["md-folder_key"] = 0xf08ac, + ["md-folder_key_network"] = 0xf08ad, + ["md-folder_key_network_outline"] = 0xf0c80, + ["md-folder_key_outline"] = 0xf10ec, + ["md-folder_lock"] = 0xf0250, + ["md-folder_lock_open"] = 0xf0251, + ["md-folder_lock_open_outline"] = 0xf1aa7, + ["md-folder_lock_outline"] = 0xf1aa8, + ["md-folder_marker"] = 0xf126d, + ["md-folder_marker_outline"] = 0xf126e, + ["md-folder_move"] = 0xf0252, + ["md-folder_move_outline"] = 0xf1246, + ["md-folder_multiple"] = 0xf0253, + ["md-folder_multiple_image"] = 0xf0254, + ["md-folder_multiple_outline"] = 0xf0255, + ["md-folder_multiple_plus"] = 0xf147e, + ["md-folder_multiple_plus_outline"] = 0xf147f, + ["md-folder_music"] = 0xf1359, + ["md-folder_music_outline"] = 0xf135a, + ["md-folder_network"] = 0xf0870, + ["md-folder_network_outline"] = 0xf0c81, + ["md-folder_off"] = 0xf19f8, + ["md-folder_off_outline"] = 0xf19f9, + ["md-folder_open"] = 0xf0770, + ["md-folder_open_outline"] = 0xf0dcf, + ["md-folder_outline"] = 0xf0256, + ["md-folder_play"] = 0xf19fa, + ["md-folder_play_outline"] = 0xf19fb, + ["md-folder_plus"] = 0xf0257, + ["md-folder_plus_outline"] = 0xf0b9d, + ["md-folder_pound"] = 0xf0d09, + ["md-folder_pound_outline"] = 0xf0d0a, + ["md-folder_question"] = 0xf19ca, + ["md-folder_question_outline"] = 0xf19cb, + ["md-folder_refresh"] = 0xf0749, + ["md-folder_refresh_outline"] = 0xf0542, + ["md-folder_remove"] = 0xf0258, + ["md-folder_remove_outline"] = 0xf0b9e, + ["md-folder_search"] = 0xf0968, + ["md-folder_search_outline"] = 0xf0969, + ["md-folder_settings"] = 0xf107d, + ["md-folder_settings_outline"] = 0xf107e, + ["md-folder_star"] = 0xf069d, + ["md-folder_star_multiple"] = 0xf13d3, + ["md-folder_star_multiple_outline"] = 0xf13d4, + ["md-folder_star_outline"] = 0xf0b9f, + ["md-folder_swap"] = 0xf0fb6, + ["md-folder_swap_outline"] = 0xf0fb7, + ["md-folder_sync"] = 0xf0d0b, + ["md-folder_sync_outline"] = 0xf0d0c, + ["md-folder_table"] = 0xf12e3, + ["md-folder_table_outline"] = 0xf12e4, + ["md-folder_text"] = 0xf0c82, + ["md-folder_text_outline"] = 0xf0c83, + ["md-folder_upload"] = 0xf0259, + ["md-folder_upload_outline"] = 0xf10ed, + ["md-folder_wrench"] = 0xf19fc, + ["md-folder_wrench_outline"] = 0xf19fd, + ["md-folder_zip"] = 0xf06eb, + ["md-folder_zip_outline"] = 0xf07b9, + ["md-font_awesome"] = 0xf003a, + ["md-food"] = 0xf025a, + ["md-food_apple"] = 0xf025b, + ["md-food_apple_outline"] = 0xf0c84, + ["md-food_croissant"] = 0xf07c8, + ["md-food_drumstick"] = 0xf141f, + ["md-food_drumstick_off"] = 0xf1468, + ["md-food_drumstick_off_outline"] = 0xf1469, + ["md-food_drumstick_outline"] = 0xf1420, + ["md-food_fork_drink"] = 0xf05f2, + ["md-food_halal"] = 0xf1572, + ["md-food_hot_dog"] = 0xf184b, + ["md-food_kosher"] = 0xf1573, + ["md-food_off"] = 0xf05f3, + ["md-food_off_outline"] = 0xf1915, + ["md-food_outline"] = 0xf1916, + ["md-food_steak"] = 0xf146a, + ["md-food_steak_off"] = 0xf146b, + ["md-food_takeout_box"] = 0xf1836, + ["md-food_takeout_box_outline"] = 0xf1837, + ["md-food_turkey"] = 0xf171c, + ["md-food_variant"] = 0xf025c, + ["md-food_variant_off"] = 0xf13e5, + ["md-foot_print"] = 0xf0f52, + ["md-football"] = 0xf025d, + ["md-football_australian"] = 0xf025e, + ["md-football_helmet"] = 0xf025f, + ["md-forest"] = 0xf1897, + ["md-forklift"] = 0xf07c9, + ["md-form_dropdown"] = 0xf1400, + ["md-form_select"] = 0xf1401, + ["md-form_textarea"] = 0xf1095, + ["md-form_textbox"] = 0xf060e, + ["md-form_textbox_lock"] = 0xf135d, + ["md-form_textbox_password"] = 0xf07f5, + ["md-format_align_bottom"] = 0xf0753, + ["md-format_align_center"] = 0xf0260, + ["md-format_align_justify"] = 0xf0261, + ["md-format_align_left"] = 0xf0262, + ["md-format_align_middle"] = 0xf0754, + ["md-format_align_right"] = 0xf0263, + ["md-format_align_top"] = 0xf0755, + ["md-format_annotation_minus"] = 0xf0abc, + ["md-format_annotation_plus"] = 0xf0646, + ["md-format_bold"] = 0xf0264, + ["md-format_clear"] = 0xf0265, + ["md-format_color_fill"] = 0xf0266, + ["md-format_color_highlight"] = 0xf0e31, + ["md-format_color_marker_cancel"] = 0xf1313, + ["md-format_color_text"] = 0xf069e, + ["md-format_columns"] = 0xf08df, + ["md-format_float_center"] = 0xf0267, + ["md-format_float_left"] = 0xf0268, + ["md-format_float_none"] = 0xf0269, + ["md-format_float_right"] = 0xf026a, + ["md-format_font"] = 0xf06d6, + ["md-format_font_size_decrease"] = 0xf09f3, + ["md-format_font_size_increase"] = 0xf09f4, + ["md-format_header_1"] = 0xf026b, + ["md-format_header_2"] = 0xf026c, + ["md-format_header_3"] = 0xf026d, + ["md-format_header_4"] = 0xf026e, + ["md-format_header_5"] = 0xf026f, + ["md-format_header_6"] = 0xf0270, + ["md-format_header_decrease"] = 0xf0271, + ["md-format_header_equal"] = 0xf0272, + ["md-format_header_increase"] = 0xf0273, + ["md-format_header_pound"] = 0xf0274, + ["md-format_horizontal_align_center"] = 0xf061e, + ["md-format_horizontal_align_left"] = 0xf061f, + ["md-format_horizontal_align_right"] = 0xf0620, + ["md-format_indent_decrease"] = 0xf0275, + ["md-format_indent_increase"] = 0xf0276, + ["md-format_italic"] = 0xf0277, + ["md-format_letter_case"] = 0xf0b34, + ["md-format_letter_case_lower"] = 0xf0b35, + ["md-format_letter_case_upper"] = 0xf0b36, + ["md-format_letter_ends_with"] = 0xf0fb8, + ["md-format_letter_matches"] = 0xf0fb9, + ["md-format_letter_spacing"] = 0xf1956, + ["md-format_letter_starts_with"] = 0xf0fba, + ["md-format_line_spacing"] = 0xf0278, + ["md-format_line_style"] = 0xf05c8, + ["md-format_line_weight"] = 0xf05c9, + ["md-format_list_bulleted"] = 0xf0279, + ["md-format_list_bulleted_square"] = 0xf0dd0, + ["md-format_list_bulleted_triangle"] = 0xf0eb2, + ["md-format_list_bulleted_type"] = 0xf027a, + ["md-format_list_checkbox"] = 0xf096a, + ["md-format_list_checks"] = 0xf0756, + ["md-format_list_group"] = 0xf1860, + ["md-format_list_numbered"] = 0xf027b, + ["md-format_list_numbered_rtl"] = 0xf0d0d, + ["md-format_list_text"] = 0xf126f, + ["md-format_overline"] = 0xf0eb3, + ["md-format_page_break"] = 0xf06d7, + ["md-format_page_split"] = 0xf1917, + ["md-format_paint"] = 0xf027c, + ["md-format_paragraph"] = 0xf027d, + ["md-format_pilcrow"] = 0xf06d8, + ["md-format_quote_close"] = 0xf027e, + ["md-format_quote_close_outline"] = 0xf11a8, + ["md-format_quote_open"] = 0xf0757, + ["md-format_quote_open_outline"] = 0xf11a7, + ["md-format_rotate_90"] = 0xf06aa, + ["md-format_section"] = 0xf069f, + ["md-format_size"] = 0xf027f, + ["md-format_strikethrough"] = 0xf0280, + ["md-format_strikethrough_variant"] = 0xf0281, + ["md-format_subscript"] = 0xf0282, + ["md-format_superscript"] = 0xf0283, + ["md-format_text"] = 0xf0284, + ["md-format_text_rotation_angle_down"] = 0xf0fbb, + ["md-format_text_rotation_angle_up"] = 0xf0fbc, + ["md-format_text_rotation_down"] = 0xf0d73, + ["md-format_text_rotation_down_vertical"] = 0xf0fbd, + ["md-format_text_rotation_none"] = 0xf0d74, + ["md-format_text_rotation_up"] = 0xf0fbe, + ["md-format_text_rotation_vertical"] = 0xf0fbf, + ["md-format_text_variant"] = 0xf0e32, + ["md-format_text_variant_outline"] = 0xf150f, + ["md-format_text_wrapping_clip"] = 0xf0d0e, + ["md-format_text_wrapping_overflow"] = 0xf0d0f, + ["md-format_text_wrapping_wrap"] = 0xf0d10, + ["md-format_textbox"] = 0xf0d11, + ["md-format_textdirection_l_to_r"] = 0xf0285, + ["md-format_textdirection_r_to_l"] = 0xf0286, + ["md-format_title"] = 0xf05f4, + ["md-format_underline"] = 0xf0287, + ["md-format_underline_wavy"] = 0xf18e9, + ["md-format_vertical_align_bottom"] = 0xf0621, + ["md-format_vertical_align_center"] = 0xf0622, + ["md-format_vertical_align_top"] = 0xf0623, + ["md-format_wrap_inline"] = 0xf0288, + ["md-format_wrap_square"] = 0xf0289, + ["md-format_wrap_tight"] = 0xf028a, + ["md-format_wrap_top_bottom"] = 0xf028b, + ["md-forum"] = 0xf028c, + ["md-forum_minus"] = 0xf1aa9, + ["md-forum_minus_outline"] = 0xf1aaa, + ["md-forum_outline"] = 0xf0822, + ["md-forum_plus"] = 0xf1aab, + ["md-forum_plus_outline"] = 0xf1aac, + ["md-forum_remove"] = 0xf1aad, + ["md-forum_remove_outline"] = 0xf1aae, + ["md-forward"] = 0xf028d, + ["md-forwardburger"] = 0xf0d75, + ["md-fountain"] = 0xf096b, + ["md-fountain_pen"] = 0xf0d12, + ["md-fountain_pen_tip"] = 0xf0d13, + ["md-fraction_one_half"] = 0xf1992, + ["md-freebsd"] = 0xf08e0, + ["md-french_fries"] = 0xf1957, + ["md-frequently_asked_questions"] = 0xf0eb4, + ["md-fridge"] = 0xf0290, + ["md-fridge_alert"] = 0xf11b1, + ["md-fridge_alert_outline"] = 0xf11b2, + ["md-fridge_bottom"] = 0xf0292, + ["md-fridge_industrial"] = 0xf15ee, + ["md-fridge_industrial_alert"] = 0xf15ef, + ["md-fridge_industrial_alert_outline"] = 0xf15f0, + ["md-fridge_industrial_off"] = 0xf15f1, + ["md-fridge_industrial_off_outline"] = 0xf15f2, + ["md-fridge_industrial_outline"] = 0xf15f3, + ["md-fridge_off"] = 0xf11af, + ["md-fridge_off_outline"] = 0xf11b0, + ["md-fridge_outline"] = 0xf028f, + ["md-fridge_top"] = 0xf0291, + ["md-fridge_variant"] = 0xf15f4, + ["md-fridge_variant_alert"] = 0xf15f5, + ["md-fridge_variant_alert_outline"] = 0xf15f6, + ["md-fridge_variant_off"] = 0xf15f7, + ["md-fridge_variant_off_outline"] = 0xf15f8, + ["md-fridge_variant_outline"] = 0xf15f9, + ["md-fruit_cherries"] = 0xf1042, + ["md-fruit_cherries_off"] = 0xf13f8, + ["md-fruit_citrus"] = 0xf1043, + ["md-fruit_citrus_off"] = 0xf13f9, + ["md-fruit_grapes"] = 0xf1044, + ["md-fruit_grapes_outline"] = 0xf1045, + ["md-fruit_pear"] = 0xf1a0e, + ["md-fruit_pineapple"] = 0xf1046, + ["md-fruit_watermelon"] = 0xf1047, + ["md-fuel"] = 0xf07ca, + ["md-fuel_cell"] = 0xf18b5, + ["md-fullscreen"] = 0xf0293, + ["md-fullscreen_exit"] = 0xf0294, + ["md-function"] = 0xf0295, + ["md-function_variant"] = 0xf0871, + ["md-furigana_horizontal"] = 0xf1081, + ["md-furigana_vertical"] = 0xf1082, + ["md-fuse"] = 0xf0c85, + ["md-fuse_alert"] = 0xf142d, + ["md-fuse_blade"] = 0xf0c86, + ["md-fuse_off"] = 0xf142c, + ["md-gamepad"] = 0xf0296, + ["md-gamepad_circle"] = 0xf0e33, + ["md-gamepad_circle_down"] = 0xf0e34, + ["md-gamepad_circle_left"] = 0xf0e35, + ["md-gamepad_circle_outline"] = 0xf0e36, + ["md-gamepad_circle_right"] = 0xf0e37, + ["md-gamepad_circle_up"] = 0xf0e38, + ["md-gamepad_down"] = 0xf0e39, + ["md-gamepad_left"] = 0xf0e3a, + ["md-gamepad_outline"] = 0xf1919, + ["md-gamepad_right"] = 0xf0e3b, + ["md-gamepad_round"] = 0xf0e3c, + ["md-gamepad_round_down"] = 0xf0e3d, + ["md-gamepad_round_left"] = 0xf0e3e, + ["md-gamepad_round_outline"] = 0xf0e3f, + ["md-gamepad_round_right"] = 0xf0e40, + ["md-gamepad_round_up"] = 0xf0e41, + ["md-gamepad_square"] = 0xf0eb5, + ["md-gamepad_square_outline"] = 0xf0eb6, + ["md-gamepad_up"] = 0xf0e42, + ["md-gamepad_variant"] = 0xf0297, + ["md-gamepad_variant_outline"] = 0xf0eb7, + ["md-gamma"] = 0xf10ee, + ["md-gantry_crane"] = 0xf0dd1, + ["md-garage"] = 0xf06d9, + ["md-garage_alert"] = 0xf0872, + ["md-garage_alert_variant"] = 0xf12d5, + ["md-garage_lock"] = 0xf17fb, + ["md-garage_open"] = 0xf06da, + ["md-garage_open_variant"] = 0xf12d4, + ["md-garage_variant"] = 0xf12d3, + ["md-garage_variant_lock"] = 0xf17fc, + ["md-gas_burner"] = 0xf1a1b, + ["md-gas_cylinder"] = 0xf0647, + ["md-gas_station"] = 0xf0298, + ["md-gas_station_off"] = 0xf1409, + ["md-gas_station_off_outline"] = 0xf140a, + ["md-gas_station_outline"] = 0xf0eb8, + ["md-gate"] = 0xf0299, + ["md-gate_alert"] = 0xf17f8, + ["md-gate_and"] = 0xf08e1, + ["md-gate_arrow_left"] = 0xf17f7, + ["md-gate_arrow_right"] = 0xf1169, + ["md-gate_nand"] = 0xf08e2, + ["md-gate_nor"] = 0xf08e3, + ["md-gate_not"] = 0xf08e4, + ["md-gate_open"] = 0xf116a, + ["md-gate_or"] = 0xf08e5, + ["md-gate_xnor"] = 0xf08e6, + ["md-gate_xor"] = 0xf08e7, + ["md-gatsby"] = 0xf0e43, + ["md-gauge"] = 0xf029a, + ["md-gauge_empty"] = 0xf0873, + ["md-gauge_full"] = 0xf0874, + ["md-gauge_low"] = 0xf0875, + ["md-gavel"] = 0xf029b, + ["md-gender_female"] = 0xf029c, + ["md-gender_male"] = 0xf029d, + ["md-gender_male_female"] = 0xf029e, + ["md-gender_male_female_variant"] = 0xf113f, + ["md-gender_non_binary"] = 0xf1140, + ["md-gender_transgender"] = 0xf029f, + ["md-gentoo"] = 0xf08e8, + ["md-gesture"] = 0xf07cb, + ["md-gesture_double_tap"] = 0xf073c, + ["md-gesture_pinch"] = 0xf0abd, + ["md-gesture_spread"] = 0xf0abe, + ["md-gesture_swipe"] = 0xf0d76, + ["md-gesture_swipe_down"] = 0xf073d, + ["md-gesture_swipe_horizontal"] = 0xf0abf, + ["md-gesture_swipe_left"] = 0xf073e, + ["md-gesture_swipe_right"] = 0xf073f, + ["md-gesture_swipe_up"] = 0xf0740, + ["md-gesture_swipe_vertical"] = 0xf0ac0, + ["md-gesture_tap"] = 0xf0741, + ["md-gesture_tap_box"] = 0xf12a9, + ["md-gesture_tap_button"] = 0xf12a8, + ["md-gesture_tap_hold"] = 0xf0d77, + ["md-gesture_two_double_tap"] = 0xf0742, + ["md-gesture_two_tap"] = 0xf0743, + ["md-ghost"] = 0xf02a0, + ["md-ghost_off"] = 0xf09f5, + ["md-ghost_off_outline"] = 0xf165c, + ["md-ghost_outline"] = 0xf165d, + ["md-gift"] = 0xf0e44, + ["md-gift_off"] = 0xf16ef, + ["md-gift_off_outline"] = 0xf16f0, + ["md-gift_open"] = 0xf16f1, + ["md-gift_open_outline"] = 0xf16f2, + ["md-gift_outline"] = 0xf02a1, + ["md-git"] = 0xf02a2, + ["md-github"] = 0xf02a4, + ["md-gitlab"] = 0xf0ba0, + ["md-glass_cocktail"] = 0xf0356, + ["md-glass_cocktail_off"] = 0xf15e6, + ["md-glass_flute"] = 0xf02a5, + ["md-glass_fragile"] = 0xf1873, + ["md-glass_mug"] = 0xf02a6, + ["md-glass_mug_off"] = 0xf15e7, + ["md-glass_mug_variant"] = 0xf1116, + ["md-glass_mug_variant_off"] = 0xf15e8, + ["md-glass_pint_outline"] = 0xf130d, + ["md-glass_stange"] = 0xf02a7, + ["md-glass_tulip"] = 0xf02a8, + ["md-glass_wine"] = 0xf0876, + ["md-glasses"] = 0xf02aa, + ["md-globe_light"] = 0xf12d7, + ["md-globe_model"] = 0xf08e9, + ["md-gmail"] = 0xf02ab, + ["md-gnome"] = 0xf02ac, + ["md-go_kart"] = 0xf0d79, + ["md-go_kart_track"] = 0xf0d7a, + ["md-gog"] = 0xf0ba1, + ["md-gold"] = 0xf124f, + ["md-golf"] = 0xf0823, + ["md-golf_cart"] = 0xf11a4, + ["md-golf_tee"] = 0xf1083, + ["md-gondola"] = 0xf0686, + ["md-goodreads"] = 0xf0d7b, + ["md-google"] = 0xf02ad, + ["md-google_ads"] = 0xf0c87, + ["md-google_analytics"] = 0xf07cc, + ["md-google_assistant"] = 0xf07cd, + ["md-google_cardboard"] = 0xf02ae, + ["md-google_chrome"] = 0xf02af, + ["md-google_circles"] = 0xf02b0, + ["md-google_circles_communities"] = 0xf02b1, + ["md-google_circles_extended"] = 0xf02b2, + ["md-google_circles_group"] = 0xf02b3, + ["md-google_classroom"] = 0xf02c0, + ["md-google_cloud"] = 0xf11f6, + ["md-google_controller"] = 0xf02b4, + ["md-google_controller_off"] = 0xf02b5, + ["md-google_downasaur"] = 0xf1362, + ["md-google_drive"] = 0xf02b6, + ["md-google_earth"] = 0xf02b7, + ["md-google_fit"] = 0xf096c, + ["md-google_glass"] = 0xf02b8, + ["md-google_hangouts"] = 0xf02c9, + ["md-google_home"] = 0xf0824, + ["md-google_keep"] = 0xf06dc, + ["md-google_lens"] = 0xf09f6, + ["md-google_maps"] = 0xf05f5, + ["md-google_my_business"] = 0xf1048, + ["md-google_nearby"] = 0xf02b9, + ["md-google_play"] = 0xf02bc, + ["md-google_plus"] = 0xf02bd, + ["md-google_podcast"] = 0xf0eb9, + ["md-google_spreadsheet"] = 0xf09f7, + ["md-google_street_view"] = 0xf0c88, + ["md-google_translate"] = 0xf02bf, + ["md-gradient_horizontal"] = 0xf174a, + ["md-gradient_vertical"] = 0xf06a0, + ["md-grain"] = 0xf0d7c, + ["md-graph"] = 0xf1049, + ["md-graph_outline"] = 0xf104a, + ["md-graphql"] = 0xf0877, + ["md-grass"] = 0xf1510, + ["md-grave_stone"] = 0xf0ba2, + ["md-grease_pencil"] = 0xf0648, + ["md-greater_than"] = 0xf096d, + ["md-greater_than_or_equal"] = 0xf096e, + ["md-greenhouse"] = 0xf002d, + ["md-grid"] = 0xf02c1, + ["md-grid_large"] = 0xf0758, + ["md-grid_off"] = 0xf02c2, + ["md-grill"] = 0xf0e45, + ["md-grill_outline"] = 0xf118a, + ["md-group"] = 0xf02c3, + ["md-guitar_acoustic"] = 0xf0771, + ["md-guitar_electric"] = 0xf02c4, + ["md-guitar_pick"] = 0xf02c5, + ["md-guitar_pick_outline"] = 0xf02c6, + ["md-guy_fawkes_mask"] = 0xf0825, + ["md-gymnastics"] = 0xf1a41, + ["md-hail"] = 0xf0ac1, + ["md-hair_dryer"] = 0xf10ef, + ["md-hair_dryer_outline"] = 0xf10f0, + ["md-halloween"] = 0xf0ba3, + ["md-hamburger"] = 0xf0685, + ["md-hamburger_check"] = 0xf1776, + ["md-hamburger_minus"] = 0xf1777, + ["md-hamburger_off"] = 0xf1778, + ["md-hamburger_plus"] = 0xf1779, + ["md-hamburger_remove"] = 0xf177a, + ["md-hammer"] = 0xf08ea, + ["md-hammer_screwdriver"] = 0xf1322, + ["md-hammer_sickle"] = 0xf1887, + ["md-hammer_wrench"] = 0xf1323, + ["md-hand_back_left"] = 0xf0e46, + ["md-hand_back_left_off"] = 0xf1830, + ["md-hand_back_left_off_outline"] = 0xf1832, + ["md-hand_back_left_outline"] = 0xf182c, + ["md-hand_back_right"] = 0xf0e47, + ["md-hand_back_right_off"] = 0xf1831, + ["md-hand_back_right_off_outline"] = 0xf1833, + ["md-hand_back_right_outline"] = 0xf182d, + ["md-hand_clap"] = 0xf194b, + ["md-hand_clap_off"] = 0xf1a42, + ["md-hand_coin"] = 0xf188f, + ["md-hand_coin_outline"] = 0xf1890, + ["md-hand_extended"] = 0xf18b6, + ["md-hand_extended_outline"] = 0xf18b7, + ["md-hand_front_left"] = 0xf182b, + ["md-hand_front_left_outline"] = 0xf182e, + ["md-hand_front_right"] = 0xf0a4f, + ["md-hand_front_right_outline"] = 0xf182f, + ["md-hand_heart"] = 0xf10f1, + ["md-hand_heart_outline"] = 0xf157e, + ["md-hand_okay"] = 0xf0a50, + ["md-hand_peace"] = 0xf0a51, + ["md-hand_peace_variant"] = 0xf0a52, + ["md-hand_pointing_down"] = 0xf0a53, + ["md-hand_pointing_left"] = 0xf0a54, + ["md-hand_pointing_right"] = 0xf02c7, + ["md-hand_pointing_up"] = 0xf0a55, + ["md-hand_saw"] = 0xf0e48, + ["md-hand_wash"] = 0xf157f, + ["md-hand_wash_outline"] = 0xf1580, + ["md-hand_water"] = 0xf139f, + ["md-hand_wave"] = 0xf1821, + ["md-hand_wave_outline"] = 0xf1822, + ["md-handball"] = 0xf0f53, + ["md-handcuffs"] = 0xf113e, + ["md-hands_pray"] = 0xf0579, + ["md-handshake"] = 0xf1218, + ["md-handshake_outline"] = 0xf15a1, + ["md-hanger"] = 0xf02c8, + ["md-hard_hat"] = 0xf096f, + ["md-harddisk"] = 0xf02ca, + ["md-harddisk_plus"] = 0xf104b, + ["md-harddisk_remove"] = 0xf104c, + ["md-hat_fedora"] = 0xf0ba4, + ["md-hazard_lights"] = 0xf0c89, + ["md-hdr"] = 0xf0d7d, + ["md-hdr_off"] = 0xf0d7e, + ["md-head"] = 0xf135e, + ["md-head_alert"] = 0xf1338, + ["md-head_alert_outline"] = 0xf1339, + ["md-head_check"] = 0xf133a, + ["md-head_check_outline"] = 0xf133b, + ["md-head_cog"] = 0xf133c, + ["md-head_cog_outline"] = 0xf133d, + ["md-head_dots_horizontal"] = 0xf133e, + ["md-head_dots_horizontal_outline"] = 0xf133f, + ["md-head_flash"] = 0xf1340, + ["md-head_flash_outline"] = 0xf1341, + ["md-head_heart"] = 0xf1342, + ["md-head_heart_outline"] = 0xf1343, + ["md-head_lightbulb"] = 0xf1344, + ["md-head_lightbulb_outline"] = 0xf1345, + ["md-head_minus"] = 0xf1346, + ["md-head_minus_outline"] = 0xf1347, + ["md-head_outline"] = 0xf135f, + ["md-head_plus"] = 0xf1348, + ["md-head_plus_outline"] = 0xf1349, + ["md-head_question"] = 0xf134a, + ["md-head_question_outline"] = 0xf134b, + ["md-head_remove"] = 0xf134c, + ["md-head_remove_outline"] = 0xf134d, + ["md-head_snowflake"] = 0xf134e, + ["md-head_snowflake_outline"] = 0xf134f, + ["md-head_sync"] = 0xf1350, + ["md-head_sync_outline"] = 0xf1351, + ["md-headphones"] = 0xf02cb, + ["md-headphones_bluetooth"] = 0xf0970, + ["md-headphones_box"] = 0xf02cc, + ["md-headphones_off"] = 0xf07ce, + ["md-headphones_settings"] = 0xf02cd, + ["md-headset"] = 0xf02ce, + ["md-headset_dock"] = 0xf02cf, + ["md-headset_off"] = 0xf02d0, + ["md-heart"] = 0xf08d0, + ["md-heart_box"] = 0xf02d2, + ["md-heart_box_outline"] = 0xf02d3, + ["md-heart_broken"] = 0xf02d4, + ["md-heart_broken_outline"] = 0xf0d14, + ["md-heart_circle"] = 0xf0971, + ["md-heart_circle_outline"] = 0xf0972, + ["md-heart_cog"] = 0xf1663, + ["md-heart_cog_outline"] = 0xf1664, + ["md-heart_flash"] = 0xf0ef9, + ["md-heart_half"] = 0xf06df, + ["md-heart_half_full"] = 0xf06de, + ["md-heart_half_outline"] = 0xf06e0, + ["md-heart_minus"] = 0xf142f, + ["md-heart_minus_outline"] = 0xf1432, + ["md-heart_multiple"] = 0xf0a56, + ["md-heart_multiple_outline"] = 0xf0a57, + ["md-heart_off"] = 0xf0759, + ["md-heart_off_outline"] = 0xf1434, + ["md-heart_outline"] = 0xf18a0, + ["md-heart_plus"] = 0xf142e, + ["md-heart_plus_outline"] = 0xf1431, + ["md-heart_pulse"] = 0xf05f6, + ["md-heart_remove"] = 0xf1430, + ["md-heart_remove_outline"] = 0xf1433, + ["md-heart_settings"] = 0xf1665, + ["md-heart_settings_outline"] = 0xf1666, + ["md-heat_pump"] = 0xf1a43, + ["md-heat_pump_outline"] = 0xf1a44, + ["md-heat_wave"] = 0xf1a45, + ["md-heating_coil"] = 0xf1aaf, + ["md-helicopter"] = 0xf0ac2, + ["md-help"] = 0xf02d6, + ["md-help_box"] = 0xf078b, + ["md-help_circle"] = 0xf02d7, + ["md-help_circle_outline"] = 0xf0625, + ["md-help_network"] = 0xf06f5, + ["md-help_network_outline"] = 0xf0c8a, + ["md-help_rhombus"] = 0xf0ba5, + ["md-help_rhombus_outline"] = 0xf0ba6, + ["md-hexadecimal"] = 0xf12a7, + ["md-hexagon"] = 0xf02d8, + ["md-hexagon_multiple"] = 0xf06e1, + ["md-hexagon_multiple_outline"] = 0xf10f2, + ["md-hexagon_outline"] = 0xf02d9, + ["md-hexagon_slice_1"] = 0xf0ac3, + ["md-hexagon_slice_2"] = 0xf0ac4, + ["md-hexagon_slice_3"] = 0xf0ac5, + ["md-hexagon_slice_4"] = 0xf0ac6, + ["md-hexagon_slice_5"] = 0xf0ac7, + ["md-hexagon_slice_6"] = 0xf0ac8, + ["md-hexagram"] = 0xf0ac9, + ["md-hexagram_outline"] = 0xf0aca, + ["md-high_definition"] = 0xf07cf, + ["md-high_definition_box"] = 0xf0878, + ["md-highway"] = 0xf05f7, + ["md-hiking"] = 0xf0d7f, + ["md-history"] = 0xf02da, + ["md-hockey_puck"] = 0xf0879, + ["md-hockey_sticks"] = 0xf087a, + ["md-hololens"] = 0xf02db, + ["md-home"] = 0xf02dc, + ["md-home_account"] = 0xf0826, + ["md-home_alert"] = 0xf087b, + ["md-home_alert_outline"] = 0xf15d0, + ["md-home_analytics"] = 0xf0eba, + ["md-home_assistant"] = 0xf07d0, + ["md-home_automation"] = 0xf07d1, + ["md-home_battery"] = 0xf1901, + ["md-home_battery_outline"] = 0xf1902, + ["md-home_circle"] = 0xf07d2, + ["md-home_circle_outline"] = 0xf104d, + ["md-home_city"] = 0xf0d15, + ["md-home_city_outline"] = 0xf0d16, + ["md-home_clock"] = 0xf1a12, + ["md-home_clock_outline"] = 0xf1a13, + ["md-home_edit"] = 0xf1159, + ["md-home_edit_outline"] = 0xf115a, + ["md-home_export_outline"] = 0xf0f9b, + ["md-home_flood"] = 0xf0efa, + ["md-home_floor_0"] = 0xf0dd2, + ["md-home_floor_1"] = 0xf0d80, + ["md-home_floor_2"] = 0xf0d81, + ["md-home_floor_3"] = 0xf0d82, + ["md-home_floor_a"] = 0xf0d83, + ["md-home_floor_b"] = 0xf0d84, + ["md-home_floor_g"] = 0xf0d85, + ["md-home_floor_l"] = 0xf0d86, + ["md-home_floor_negative_1"] = 0xf0dd3, + ["md-home_group"] = 0xf0dd4, + ["md-home_group_minus"] = 0xf19c1, + ["md-home_group_plus"] = 0xf19c0, + ["md-home_group_remove"] = 0xf19c2, + ["md-home_heart"] = 0xf0827, + ["md-home_import_outline"] = 0xf0f9c, + ["md-home_lightbulb"] = 0xf1251, + ["md-home_lightbulb_outline"] = 0xf1252, + ["md-home_lightning_bolt"] = 0xf1903, + ["md-home_lightning_bolt_outline"] = 0xf1904, + ["md-home_lock"] = 0xf08eb, + ["md-home_lock_open"] = 0xf08ec, + ["md-home_map_marker"] = 0xf05f8, + ["md-home_minus"] = 0xf0974, + ["md-home_minus_outline"] = 0xf13d5, + ["md-home_modern"] = 0xf02dd, + ["md-home_off"] = 0xf1a46, + ["md-home_off_outline"] = 0xf1a47, + ["md-home_outline"] = 0xf06a1, + ["md-home_plus"] = 0xf0975, + ["md-home_plus_outline"] = 0xf13d6, + ["md-home_remove"] = 0xf1247, + ["md-home_remove_outline"] = 0xf13d7, + ["md-home_roof"] = 0xf112b, + ["md-home_search"] = 0xf13b0, + ["md-home_search_outline"] = 0xf13b1, + ["md-home_switch"] = 0xf1794, + ["md-home_switch_outline"] = 0xf1795, + ["md-home_thermometer"] = 0xf0f54, + ["md-home_thermometer_outline"] = 0xf0f55, + ["md-home_variant"] = 0xf02de, + ["md-home_variant_outline"] = 0xf0ba7, + ["md-hook"] = 0xf06e2, + ["md-hook_off"] = 0xf06e3, + ["md-hoop_house"] = 0xf0e56, + ["md-hops"] = 0xf02df, + ["md-horizontal_rotate_clockwise"] = 0xf10f3, + ["md-horizontal_rotate_counterclockwise"] = 0xf10f4, + ["md-horse"] = 0xf15bf, + ["md-horse_human"] = 0xf15c0, + ["md-horse_variant"] = 0xf15c1, + ["md-horse_variant_fast"] = 0xf186e, + ["md-horseshoe"] = 0xf0a58, + ["md-hospital"] = 0xf0ff6, + ["md-hospital_box"] = 0xf02e0, + ["md-hospital_box_outline"] = 0xf0ff7, + ["md-hospital_building"] = 0xf02e1, + ["md-hospital_marker"] = 0xf02e2, + ["md-hot_tub"] = 0xf0828, + ["md-hours_24"] = 0xf1478, + ["md-hubspot"] = 0xf0d17, + ["md-hulu"] = 0xf0829, + ["md-human"] = 0xf02e6, + ["md-human_baby_changing_table"] = 0xf138b, + ["md-human_cane"] = 0xf1581, + ["md-human_capacity_decrease"] = 0xf159b, + ["md-human_capacity_increase"] = 0xf159c, + ["md-human_child"] = 0xf02e7, + ["md-human_dolly"] = 0xf1980, + ["md-human_edit"] = 0xf14e8, + ["md-human_female"] = 0xf0649, + ["md-human_female_boy"] = 0xf0a59, + ["md-human_female_dance"] = 0xf15c9, + ["md-human_female_female"] = 0xf0a5a, + ["md-human_female_girl"] = 0xf0a5b, + ["md-human_greeting"] = 0xf17c4, + ["md-human_greeting_proximity"] = 0xf159d, + ["md-human_greeting_variant"] = 0xf064a, + ["md-human_handsdown"] = 0xf064b, + ["md-human_handsup"] = 0xf064c, + ["md-human_male"] = 0xf064d, + ["md-human_male_board"] = 0xf0890, + ["md-human_male_board_poll"] = 0xf0846, + ["md-human_male_boy"] = 0xf0a5c, + ["md-human_male_child"] = 0xf138c, + ["md-human_male_female"] = 0xf02e8, + ["md-human_male_female_child"] = 0xf1823, + ["md-human_male_girl"] = 0xf0a5d, + ["md-human_male_height"] = 0xf0efb, + ["md-human_male_height_variant"] = 0xf0efc, + ["md-human_male_male"] = 0xf0a5e, + ["md-human_non_binary"] = 0xf1848, + ["md-human_pregnant"] = 0xf05cf, + ["md-human_queue"] = 0xf1571, + ["md-human_scooter"] = 0xf11e9, + ["md-human_wheelchair"] = 0xf138d, + ["md-human_white_cane"] = 0xf1981, + ["md-humble_bundle"] = 0xf0744, + ["md-hvac"] = 0xf1352, + ["md-hvac_off"] = 0xf159e, + ["md-hydraulic_oil_level"] = 0xf1324, + ["md-hydraulic_oil_temperature"] = 0xf1325, + ["md-hydro_power"] = 0xf12e5, + ["md-hydrogen_station"] = 0xf1894, + ["md-ice_cream"] = 0xf082a, + ["md-ice_cream_off"] = 0xf0e52, + ["md-ice_pop"] = 0xf0efd, + ["md-id_card"] = 0xf0fc0, + ["md-identifier"] = 0xf0efe, + ["md-ideogram_cjk"] = 0xf1331, + ["md-ideogram_cjk_variant"] = 0xf1332, + ["md-image"] = 0xf02e9, + ["md-image_album"] = 0xf02ea, + ["md-image_area"] = 0xf02eb, + ["md-image_area_close"] = 0xf02ec, + ["md-image_auto_adjust"] = 0xf0fc1, + ["md-image_broken"] = 0xf02ed, + ["md-image_broken_variant"] = 0xf02ee, + ["md-image_edit"] = 0xf11e3, + ["md-image_edit_outline"] = 0xf11e4, + ["md-image_filter_black_white"] = 0xf02f0, + ["md-image_filter_center_focus"] = 0xf02f1, + ["md-image_filter_center_focus_strong"] = 0xf0eff, + ["md-image_filter_center_focus_strong_outline"] = 0xf0f00, + ["md-image_filter_center_focus_weak"] = 0xf02f2, + ["md-image_filter_drama"] = 0xf02f3, + ["md-image_filter_frames"] = 0xf02f4, + ["md-image_filter_hdr"] = 0xf0509, + ["md-image_filter_none"] = 0xf02f6, + ["md-image_filter_tilt_shift"] = 0xf02f7, + ["md-image_filter_vintage"] = 0xf02f8, + ["md-image_frame"] = 0xf0e49, + ["md-image_lock"] = 0xf1ab0, + ["md-image_lock_outline"] = 0xf1ab1, + ["md-image_marker"] = 0xf177b, + ["md-image_marker_outline"] = 0xf177c, + ["md-image_minus"] = 0xf1419, + ["md-image_move"] = 0xf09f8, + ["md-image_multiple"] = 0xf02f9, + ["md-image_multiple_outline"] = 0xf02ef, + ["md-image_off"] = 0xf082b, + ["md-image_off_outline"] = 0xf11d1, + ["md-image_outline"] = 0xf0976, + ["md-image_plus"] = 0xf087c, + ["md-image_refresh"] = 0xf19fe, + ["md-image_refresh_outline"] = 0xf19ff, + ["md-image_remove"] = 0xf1418, + ["md-image_search"] = 0xf0977, + ["md-image_search_outline"] = 0xf0978, + ["md-image_size_select_actual"] = 0xf0c8d, + ["md-image_size_select_large"] = 0xf0c8e, + ["md-image_size_select_small"] = 0xf0c8f, + ["md-image_sync"] = 0xf1a00, + ["md-image_sync_outline"] = 0xf1a01, + ["md-image_text"] = 0xf160d, + ["md-import"] = 0xf02fa, + ["md-inbox"] = 0xf0687, + ["md-inbox_arrow_down"] = 0xf02fb, + ["md-inbox_arrow_down_outline"] = 0xf1270, + ["md-inbox_arrow_up"] = 0xf03d1, + ["md-inbox_arrow_up_outline"] = 0xf1271, + ["md-inbox_full"] = 0xf1272, + ["md-inbox_full_outline"] = 0xf1273, + ["md-inbox_multiple"] = 0xf08b0, + ["md-inbox_multiple_outline"] = 0xf0ba8, + ["md-inbox_outline"] = 0xf1274, + ["md-inbox_remove"] = 0xf159f, + ["md-inbox_remove_outline"] = 0xf15a0, + ["md-incognito"] = 0xf05f9, + ["md-incognito_circle"] = 0xf1421, + ["md-incognito_circle_off"] = 0xf1422, + ["md-incognito_off"] = 0xf0075, + ["md-induction"] = 0xf184c, + ["md-infinity"] = 0xf06e4, + ["md-information"] = 0xf02fc, + ["md-information_off"] = 0xf178c, + ["md-information_off_outline"] = 0xf178d, + ["md-information_outline"] = 0xf02fd, + ["md-information_variant"] = 0xf064e, + ["md-instagram"] = 0xf02fe, + ["md-instrument_triangle"] = 0xf104e, + ["md-integrated_circuit_chip"] = 0xf1913, + ["md-invert_colors"] = 0xf0301, + ["md-invert_colors_off"] = 0xf0e4a, + ["md-iobroker"] = 0xf12e8, + ["md-ip"] = 0xf0a5f, + ["md-ip_network"] = 0xf0a60, + ["md-ip_network_outline"] = 0xf0c90, + ["md-ip_outline"] = 0xf1982, + ["md-ipod"] = 0xf0c91, + ["md-iron"] = 0xf1824, + ["md-iron_board"] = 0xf1838, + ["md-iron_outline"] = 0xf1825, + ["md-island"] = 0xf104f, + ["md-iv_bag"] = 0xf10b9, + ["md-jabber"] = 0xf0dd5, + ["md-jeepney"] = 0xf0302, + ["md-jellyfish"] = 0xf0f01, + ["md-jellyfish_outline"] = 0xf0f02, + ["md-jira"] = 0xf0303, + ["md-jquery"] = 0xf087d, + ["md-jsfiddle"] = 0xf0304, + ["md-jump_rope"] = 0xf12ff, + ["md-kabaddi"] = 0xf0d87, + ["md-kangaroo"] = 0xf1558, + ["md-karate"] = 0xf082c, + ["md-kayaking"] = 0xf08af, + ["md-keg"] = 0xf0305, + ["md-kettle"] = 0xf05fa, + ["md-kettle_alert"] = 0xf1317, + ["md-kettle_alert_outline"] = 0xf1318, + ["md-kettle_off"] = 0xf131b, + ["md-kettle_off_outline"] = 0xf131c, + ["md-kettle_outline"] = 0xf0f56, + ["md-kettle_pour_over"] = 0xf173c, + ["md-kettle_steam"] = 0xf1319, + ["md-kettle_steam_outline"] = 0xf131a, + ["md-kettlebell"] = 0xf1300, + ["md-key"] = 0xf0306, + ["md-key_alert"] = 0xf1983, + ["md-key_alert_outline"] = 0xf1984, + ["md-key_arrow_right"] = 0xf1312, + ["md-key_chain"] = 0xf1574, + ["md-key_chain_variant"] = 0xf1575, + ["md-key_change"] = 0xf0307, + ["md-key_link"] = 0xf119f, + ["md-key_minus"] = 0xf0308, + ["md-key_outline"] = 0xf0dd6, + ["md-key_plus"] = 0xf0309, + ["md-key_remove"] = 0xf030a, + ["md-key_star"] = 0xf119e, + ["md-key_variant"] = 0xf030b, + ["md-key_wireless"] = 0xf0fc2, + ["md-keyboard"] = 0xf030c, + ["md-keyboard_backspace"] = 0xf030d, + ["md-keyboard_caps"] = 0xf030e, + ["md-keyboard_close"] = 0xf030f, + ["md-keyboard_esc"] = 0xf12b7, + ["md-keyboard_f1"] = 0xf12ab, + ["md-keyboard_f10"] = 0xf12b4, + ["md-keyboard_f11"] = 0xf12b5, + ["md-keyboard_f12"] = 0xf12b6, + ["md-keyboard_f2"] = 0xf12ac, + ["md-keyboard_f3"] = 0xf12ad, + ["md-keyboard_f4"] = 0xf12ae, + ["md-keyboard_f5"] = 0xf12af, + ["md-keyboard_f6"] = 0xf12b0, + ["md-keyboard_f7"] = 0xf12b1, + ["md-keyboard_f8"] = 0xf12b2, + ["md-keyboard_f9"] = 0xf12b3, + ["md-keyboard_off"] = 0xf0310, + ["md-keyboard_off_outline"] = 0xf0e4b, + ["md-keyboard_outline"] = 0xf097b, + ["md-keyboard_return"] = 0xf0311, + ["md-keyboard_settings"] = 0xf09f9, + ["md-keyboard_settings_outline"] = 0xf09fa, + ["md-keyboard_space"] = 0xf1050, + ["md-keyboard_tab"] = 0xf0312, + ["md-keyboard_tab_reverse"] = 0xf0325, + ["md-keyboard_variant"] = 0xf0313, + ["md-khanda"] = 0xf10fd, + ["md-kickstarter"] = 0xf0745, + ["md-kite"] = 0xf1985, + ["md-kite_outline"] = 0xf1986, + ["md-kitesurfing"] = 0xf1744, + ["md-klingon"] = 0xf135b, + ["md-knife"] = 0xf09fb, + ["md-knife_military"] = 0xf09fc, + ["md-koala"] = 0xf173f, + ["md-kodi"] = 0xf0314, + ["md-kubernetes"] = 0xf10fe, + ["md-label"] = 0xf0315, + ["md-label_multiple"] = 0xf1375, + ["md-label_multiple_outline"] = 0xf1376, + ["md-label_off"] = 0xf0acb, + ["md-label_off_outline"] = 0xf0acc, + ["md-label_outline"] = 0xf0316, + ["md-label_percent"] = 0xf12ea, + ["md-label_percent_outline"] = 0xf12eb, + ["md-label_variant"] = 0xf0acd, + ["md-label_variant_outline"] = 0xf0ace, + ["md-ladder"] = 0xf15a2, + ["md-ladybug"] = 0xf082d, + ["md-lambda"] = 0xf0627, + ["md-lamp"] = 0xf06b5, + ["md-lamp_outline"] = 0xf17d0, + ["md-lamps"] = 0xf1576, + ["md-lamps_outline"] = 0xf17d1, + ["md-lan"] = 0xf0317, + ["md-lan_check"] = 0xf12aa, + ["md-lan_connect"] = 0xf0318, + ["md-lan_disconnect"] = 0xf0319, + ["md-lan_pending"] = 0xf031a, + ["md-land_fields"] = 0xf1ab2, + ["md-land_plots"] = 0xf1ab3, + ["md-land_plots_circle"] = 0xf1ab4, + ["md-land_plots_circle_variant"] = 0xf1ab5, + ["md-land_rows_horizontal"] = 0xf1ab6, + ["md-land_rows_vertical"] = 0xf1ab7, + ["md-landslide"] = 0xf1a48, + ["md-landslide_outline"] = 0xf1a49, + ["md-language_c"] = 0xf0671, + ["md-language_cpp"] = 0xf0672, + ["md-language_csharp"] = 0xf031b, + ["md-language_css3"] = 0xf031c, + ["md-language_fortran"] = 0xf121a, + ["md-language_go"] = 0xf07d3, + ["md-language_haskell"] = 0xf0c92, + ["md-language_html5"] = 0xf031d, + ["md-language_java"] = 0xf0b37, + ["md-language_javascript"] = 0xf031e, + ["md-language_kotlin"] = 0xf1219, + ["md-language_lua"] = 0xf08b1, + ["md-language_markdown"] = 0xf0354, + ["md-language_markdown_outline"] = 0xf0f5b, + ["md-language_php"] = 0xf031f, + ["md-language_python"] = 0xf0320, + ["md-language_r"] = 0xf07d4, + ["md-language_ruby"] = 0xf0d2d, + ["md-language_ruby_on_rails"] = 0xf0acf, + ["md-language_rust"] = 0xf1617, + ["md-language_swift"] = 0xf06e5, + ["md-language_typescript"] = 0xf06e6, + ["md-language_xaml"] = 0xf0673, + ["md-laptop"] = 0xf0322, + ["md-laptop_account"] = 0xf1a4a, + ["md-laptop_off"] = 0xf06e7, + ["md-laravel"] = 0xf0ad0, + ["md-laser_pointer"] = 0xf1484, + ["md-lasso"] = 0xf0f03, + ["md-lastpass"] = 0xf0446, + ["md-latitude"] = 0xf0f57, + ["md-launch"] = 0xf0327, + ["md-lava_lamp"] = 0xf07d5, + ["md-layers"] = 0xf0328, + ["md-layers_edit"] = 0xf1892, + ["md-layers_minus"] = 0xf0e4c, + ["md-layers_off"] = 0xf0329, + ["md-layers_off_outline"] = 0xf09fd, + ["md-layers_outline"] = 0xf09fe, + ["md-layers_plus"] = 0xf0e4d, + ["md-layers_remove"] = 0xf0e4e, + ["md-layers_search"] = 0xf1206, + ["md-layers_search_outline"] = 0xf1207, + ["md-layers_triple"] = 0xf0f58, + ["md-layers_triple_outline"] = 0xf0f59, + ["md-lead_pencil"] = 0xf064f, + ["md-leaf"] = 0xf032a, + ["md-leaf_circle"] = 0xf1905, + ["md-leaf_circle_outline"] = 0xf1906, + ["md-leaf_maple"] = 0xf0c93, + ["md-leaf_maple_off"] = 0xf12da, + ["md-leaf_off"] = 0xf12d9, + ["md-leak"] = 0xf0dd7, + ["md-leak_off"] = 0xf0dd8, + ["md-lecturn"] = 0xf1af0, + ["md-led_off"] = 0xf032b, + ["md-led_on"] = 0xf032c, + ["md-led_outline"] = 0xf032d, + ["md-led_strip"] = 0xf07d6, + ["md-led_strip_variant"] = 0xf1051, + ["md-led_strip_variant_off"] = 0xf1a4b, + ["md-led_variant_off"] = 0xf032e, + ["md-led_variant_on"] = 0xf032f, + ["md-led_variant_outline"] = 0xf0330, + ["md-leek"] = 0xf117d, + ["md-less_than"] = 0xf097c, + ["md-less_than_or_equal"] = 0xf097d, + ["md-library"] = 0xf0331, + ["md-library_outline"] = 0xf1a22, + ["md-library_shelves"] = 0xf0ba9, + ["md-license"] = 0xf0fc3, + ["md-lifebuoy"] = 0xf087e, + ["md-light_flood_down"] = 0xf1987, + ["md-light_flood_up"] = 0xf1988, + ["md-light_recessed"] = 0xf179b, + ["md-light_switch"] = 0xf097e, + ["md-light_switch_off"] = 0xf1a24, + ["md-lightbulb"] = 0xf0335, + ["md-lightbulb_alert"] = 0xf19e1, + ["md-lightbulb_alert_outline"] = 0xf19e2, + ["md-lightbulb_auto"] = 0xf1800, + ["md-lightbulb_auto_outline"] = 0xf1801, + ["md-lightbulb_cfl"] = 0xf1208, + ["md-lightbulb_cfl_off"] = 0xf1209, + ["md-lightbulb_cfl_spiral"] = 0xf1275, + ["md-lightbulb_cfl_spiral_off"] = 0xf12c3, + ["md-lightbulb_fluorescent_tube"] = 0xf1804, + ["md-lightbulb_fluorescent_tube_outline"] = 0xf1805, + ["md-lightbulb_group"] = 0xf1253, + ["md-lightbulb_group_off"] = 0xf12cd, + ["md-lightbulb_group_off_outline"] = 0xf12ce, + ["md-lightbulb_group_outline"] = 0xf1254, + ["md-lightbulb_multiple"] = 0xf1255, + ["md-lightbulb_multiple_off"] = 0xf12cf, + ["md-lightbulb_multiple_off_outline"] = 0xf12d0, + ["md-lightbulb_multiple_outline"] = 0xf1256, + ["md-lightbulb_night"] = 0xf1a4c, + ["md-lightbulb_night_outline"] = 0xf1a4d, + ["md-lightbulb_off"] = 0xf0e4f, + ["md-lightbulb_off_outline"] = 0xf0e50, + ["md-lightbulb_on"] = 0xf06e8, + ["md-lightbulb_on_10"] = 0xf1a4e, + ["md-lightbulb_on_20"] = 0xf1a4f, + ["md-lightbulb_on_30"] = 0xf1a50, + ["md-lightbulb_on_40"] = 0xf1a51, + ["md-lightbulb_on_50"] = 0xf1a52, + ["md-lightbulb_on_60"] = 0xf1a53, + ["md-lightbulb_on_70"] = 0xf1a54, + ["md-lightbulb_on_80"] = 0xf1a55, + ["md-lightbulb_on_90"] = 0xf1a56, + ["md-lightbulb_on_outline"] = 0xf06e9, + ["md-lightbulb_outline"] = 0xf0336, + ["md-lightbulb_question"] = 0xf19e3, + ["md-lightbulb_question_outline"] = 0xf19e4, + ["md-lightbulb_spot"] = 0xf17f4, + ["md-lightbulb_spot_off"] = 0xf17f5, + ["md-lightbulb_variant"] = 0xf1802, + ["md-lightbulb_variant_outline"] = 0xf1803, + ["md-lighthouse"] = 0xf09ff, + ["md-lighthouse_on"] = 0xf0a00, + ["md-lightning_bolt"] = 0xf140b, + ["md-lightning_bolt_circle"] = 0xf0820, + ["md-lightning_bolt_outline"] = 0xf140c, + ["md-line_scan"] = 0xf0624, + ["md-lingerie"] = 0xf1476, + ["md-link"] = 0xf0337, + ["md-link_box"] = 0xf0d1a, + ["md-link_box_outline"] = 0xf0d1b, + ["md-link_box_variant"] = 0xf0d1c, + ["md-link_box_variant_outline"] = 0xf0d1d, + ["md-link_lock"] = 0xf10ba, + ["md-link_off"] = 0xf0338, + ["md-link_plus"] = 0xf0c94, + ["md-link_variant"] = 0xf0339, + ["md-link_variant_minus"] = 0xf10ff, + ["md-link_variant_off"] = 0xf033a, + ["md-link_variant_plus"] = 0xf1100, + ["md-link_variant_remove"] = 0xf1101, + ["md-linkedin"] = 0xf033b, + ["md-linux"] = 0xf033d, + ["md-linux_mint"] = 0xf08ed, + ["md-lipstick"] = 0xf13b5, + ["md-liquid_spot"] = 0xf1826, + ["md-liquor"] = 0xf191e, + ["md-list_status"] = 0xf15ab, + ["md-litecoin"] = 0xf0a61, + ["md-loading"] = 0xf0772, + ["md-location_enter"] = 0xf0fc4, + ["md-location_exit"] = 0xf0fc5, + ["md-lock"] = 0xf033e, + ["md-lock_alert"] = 0xf08ee, + ["md-lock_alert_outline"] = 0xf15d1, + ["md-lock_check"] = 0xf139a, + ["md-lock_check_outline"] = 0xf16a8, + ["md-lock_clock"] = 0xf097f, + ["md-lock_minus"] = 0xf16a9, + ["md-lock_minus_outline"] = 0xf16aa, + ["md-lock_off"] = 0xf1671, + ["md-lock_off_outline"] = 0xf1672, + ["md-lock_open"] = 0xf033f, + ["md-lock_open_alert"] = 0xf139b, + ["md-lock_open_alert_outline"] = 0xf15d2, + ["md-lock_open_check"] = 0xf139c, + ["md-lock_open_check_outline"] = 0xf16ab, + ["md-lock_open_minus"] = 0xf16ac, + ["md-lock_open_minus_outline"] = 0xf16ad, + ["md-lock_open_outline"] = 0xf0340, + ["md-lock_open_plus"] = 0xf16ae, + ["md-lock_open_plus_outline"] = 0xf16af, + ["md-lock_open_remove"] = 0xf16b0, + ["md-lock_open_remove_outline"] = 0xf16b1, + ["md-lock_open_variant"] = 0xf0fc6, + ["md-lock_open_variant_outline"] = 0xf0fc7, + ["md-lock_outline"] = 0xf0341, + ["md-lock_pattern"] = 0xf06ea, + ["md-lock_plus"] = 0xf05fb, + ["md-lock_plus_outline"] = 0xf16b2, + ["md-lock_question"] = 0xf08ef, + ["md-lock_remove"] = 0xf16b3, + ["md-lock_remove_outline"] = 0xf16b4, + ["md-lock_reset"] = 0xf0773, + ["md-lock_smart"] = 0xf08b2, + ["md-locker"] = 0xf07d7, + ["md-locker_multiple"] = 0xf07d8, + ["md-login"] = 0xf0342, + ["md-logout"] = 0xf0343, + ["md-logout_variant"] = 0xf05fd, + ["md-longitude"] = 0xf0f5a, + ["md-looks"] = 0xf0344, + ["md-lotion"] = 0xf1582, + ["md-lotion_outline"] = 0xf1583, + ["md-lotion_plus"] = 0xf1584, + ["md-lotion_plus_outline"] = 0xf1585, + ["md-loupe"] = 0xf0345, + ["md-lumx"] = 0xf0346, + ["md-lungs"] = 0xf1084, + ["md-mace"] = 0xf1843, + ["md-magazine_pistol"] = 0xf0324, + ["md-magazine_rifle"] = 0xf0323, + ["md-magic_staff"] = 0xf1844, + ["md-magnet"] = 0xf0347, + ["md-magnet_on"] = 0xf0348, + ["md-magnify"] = 0xf0349, + ["md-magnify_close"] = 0xf0980, + ["md-magnify_expand"] = 0xf1874, + ["md-magnify_minus"] = 0xf034a, + ["md-magnify_minus_cursor"] = 0xf0a62, + ["md-magnify_minus_outline"] = 0xf06ec, + ["md-magnify_plus"] = 0xf034b, + ["md-magnify_plus_cursor"] = 0xf0a63, + ["md-magnify_plus_outline"] = 0xf06ed, + ["md-magnify_remove_cursor"] = 0xf120c, + ["md-magnify_remove_outline"] = 0xf120d, + ["md-magnify_scan"] = 0xf1276, + ["md-mail"] = 0xf0ebb, + ["md-mailbox"] = 0xf06ee, + ["md-mailbox_open"] = 0xf0d88, + ["md-mailbox_open_outline"] = 0xf0d89, + ["md-mailbox_open_up"] = 0xf0d8a, + ["md-mailbox_open_up_outline"] = 0xf0d8b, + ["md-mailbox_outline"] = 0xf0d8c, + ["md-mailbox_up"] = 0xf0d8d, + ["md-mailbox_up_outline"] = 0xf0d8e, + ["md-manjaro"] = 0xf160a, + ["md-map"] = 0xf034d, + ["md-map_check"] = 0xf0ebc, + ["md-map_check_outline"] = 0xf0ebd, + ["md-map_clock"] = 0xf0d1e, + ["md-map_clock_outline"] = 0xf0d1f, + ["md-map_legend"] = 0xf0a01, + ["md-map_marker"] = 0xf034e, + ["md-map_marker_account"] = 0xf18e3, + ["md-map_marker_account_outline"] = 0xf18e4, + ["md-map_marker_alert"] = 0xf0f05, + ["md-map_marker_alert_outline"] = 0xf0f06, + ["md-map_marker_check"] = 0xf0c95, + ["md-map_marker_check_outline"] = 0xf12fb, + ["md-map_marker_circle"] = 0xf034f, + ["md-map_marker_distance"] = 0xf08f0, + ["md-map_marker_down"] = 0xf1102, + ["md-map_marker_left"] = 0xf12db, + ["md-map_marker_left_outline"] = 0xf12dd, + ["md-map_marker_minus"] = 0xf0650, + ["md-map_marker_minus_outline"] = 0xf12f9, + ["md-map_marker_multiple"] = 0xf0350, + ["md-map_marker_multiple_outline"] = 0xf1277, + ["md-map_marker_off"] = 0xf0351, + ["md-map_marker_off_outline"] = 0xf12fd, + ["md-map_marker_outline"] = 0xf07d9, + ["md-map_marker_path"] = 0xf0d20, + ["md-map_marker_plus"] = 0xf0651, + ["md-map_marker_plus_outline"] = 0xf12f8, + ["md-map_marker_question"] = 0xf0f07, + ["md-map_marker_question_outline"] = 0xf0f08, + ["md-map_marker_radius"] = 0xf0352, + ["md-map_marker_radius_outline"] = 0xf12fc, + ["md-map_marker_remove"] = 0xf0f09, + ["md-map_marker_remove_outline"] = 0xf12fa, + ["md-map_marker_remove_variant"] = 0xf0f0a, + ["md-map_marker_right"] = 0xf12dc, + ["md-map_marker_right_outline"] = 0xf12de, + ["md-map_marker_star"] = 0xf1608, + ["md-map_marker_star_outline"] = 0xf1609, + ["md-map_marker_up"] = 0xf1103, + ["md-map_minus"] = 0xf0981, + ["md-map_outline"] = 0xf0982, + ["md-map_plus"] = 0xf0983, + ["md-map_search"] = 0xf0984, + ["md-map_search_outline"] = 0xf0985, + ["md-mapbox"] = 0xf0baa, + ["md-margin"] = 0xf0353, + ["md-marker"] = 0xf0652, + ["md-marker_cancel"] = 0xf0dd9, + ["md-marker_check"] = 0xf0355, + ["md-mastodon"] = 0xf0ad1, + ["md-material_design"] = 0xf0986, + ["md-material_ui"] = 0xf0357, + ["md-math_compass"] = 0xf0358, + ["md-math_cos"] = 0xf0c96, + ["md-math_integral"] = 0xf0fc8, + ["md-math_integral_box"] = 0xf0fc9, + ["md-math_log"] = 0xf1085, + ["md-math_norm"] = 0xf0fca, + ["md-math_norm_box"] = 0xf0fcb, + ["md-math_sin"] = 0xf0c97, + ["md-math_tan"] = 0xf0c98, + ["md-matrix"] = 0xf0628, + ["md-medal"] = 0xf0987, + ["md-medal_outline"] = 0xf1326, + ["md-medical_bag"] = 0xf06ef, + ["md-medical_cotton_swab"] = 0xf1ab8, + ["md-meditation"] = 0xf117b, + ["md-memory"] = 0xf035b, + ["md-menorah"] = 0xf17d4, + ["md-menorah_fire"] = 0xf17d5, + ["md-menu"] = 0xf035c, + ["md-menu_down"] = 0xf035d, + ["md-menu_down_outline"] = 0xf06b6, + ["md-menu_left"] = 0xf035e, + ["md-menu_left_outline"] = 0xf0a02, + ["md-menu_open"] = 0xf0bab, + ["md-menu_right"] = 0xf035f, + ["md-menu_right_outline"] = 0xf0a03, + ["md-menu_swap"] = 0xf0a64, + ["md-menu_swap_outline"] = 0xf0a65, + ["md-menu_up"] = 0xf0360, + ["md-menu_up_outline"] = 0xf06b7, + ["md-merge"] = 0xf0f5c, + ["md-message"] = 0xf0361, + ["md-message_alert"] = 0xf0362, + ["md-message_alert_outline"] = 0xf0a04, + ["md-message_arrow_left"] = 0xf12f2, + ["md-message_arrow_left_outline"] = 0xf12f3, + ["md-message_arrow_right"] = 0xf12f4, + ["md-message_arrow_right_outline"] = 0xf12f5, + ["md-message_badge"] = 0xf1941, + ["md-message_badge_outline"] = 0xf1942, + ["md-message_bookmark"] = 0xf15ac, + ["md-message_bookmark_outline"] = 0xf15ad, + ["md-message_bulleted"] = 0xf06a2, + ["md-message_bulleted_off"] = 0xf06a3, + ["md-message_cog"] = 0xf06f1, + ["md-message_cog_outline"] = 0xf1172, + ["md-message_draw"] = 0xf0363, + ["md-message_fast"] = 0xf19cc, + ["md-message_fast_outline"] = 0xf19cd, + ["md-message_flash"] = 0xf15a9, + ["md-message_flash_outline"] = 0xf15aa, + ["md-message_image"] = 0xf0364, + ["md-message_image_outline"] = 0xf116c, + ["md-message_lock"] = 0xf0fcc, + ["md-message_lock_outline"] = 0xf116d, + ["md-message_minus"] = 0xf116e, + ["md-message_minus_outline"] = 0xf116f, + ["md-message_off"] = 0xf164d, + ["md-message_off_outline"] = 0xf164e, + ["md-message_outline"] = 0xf0365, + ["md-message_plus"] = 0xf0653, + ["md-message_plus_outline"] = 0xf10bb, + ["md-message_processing"] = 0xf0366, + ["md-message_processing_outline"] = 0xf1170, + ["md-message_question"] = 0xf173a, + ["md-message_question_outline"] = 0xf173b, + ["md-message_reply"] = 0xf0367, + ["md-message_reply_outline"] = 0xf173d, + ["md-message_reply_text"] = 0xf0368, + ["md-message_reply_text_outline"] = 0xf173e, + ["md-message_settings"] = 0xf06f0, + ["md-message_settings_outline"] = 0xf1171, + ["md-message_star"] = 0xf069a, + ["md-message_star_outline"] = 0xf1250, + ["md-message_text"] = 0xf0369, + ["md-message_text_clock"] = 0xf1173, + ["md-message_text_clock_outline"] = 0xf1174, + ["md-message_text_fast"] = 0xf19ce, + ["md-message_text_fast_outline"] = 0xf19cf, + ["md-message_text_lock"] = 0xf0fcd, + ["md-message_text_lock_outline"] = 0xf1175, + ["md-message_text_outline"] = 0xf036a, + ["md-message_video"] = 0xf036b, + ["md-meteor"] = 0xf0629, + ["md-meter_electric"] = 0xf1a57, + ["md-meter_electric_outline"] = 0xf1a58, + ["md-meter_gas"] = 0xf1a59, + ["md-meter_gas_outline"] = 0xf1a5a, + ["md-metronome"] = 0xf07da, + ["md-metronome_tick"] = 0xf07db, + ["md-micro_sd"] = 0xf07dc, + ["md-microphone"] = 0xf036c, + ["md-microphone_minus"] = 0xf08b3, + ["md-microphone_off"] = 0xf036d, + ["md-microphone_outline"] = 0xf036e, + ["md-microphone_plus"] = 0xf08b4, + ["md-microphone_question"] = 0xf1989, + ["md-microphone_question_outline"] = 0xf198a, + ["md-microphone_settings"] = 0xf036f, + ["md-microphone_variant"] = 0xf0370, + ["md-microphone_variant_off"] = 0xf0371, + ["md-microscope"] = 0xf0654, + ["md-microsoft"] = 0xf0372, + ["md-microsoft_access"] = 0xf138e, + ["md-microsoft_azure"] = 0xf0805, + ["md-microsoft_azure_devops"] = 0xf0fd5, + ["md-microsoft_bing"] = 0xf00a4, + ["md-microsoft_dynamics_365"] = 0xf0988, + ["md-microsoft_edge"] = 0xf01e9, + ["md-microsoft_excel"] = 0xf138f, + ["md-microsoft_internet_explorer"] = 0xf0300, + ["md-microsoft_office"] = 0xf03c6, + ["md-microsoft_onedrive"] = 0xf03ca, + ["md-microsoft_onenote"] = 0xf0747, + ["md-microsoft_outlook"] = 0xf0d22, + ["md-microsoft_powerpoint"] = 0xf1390, + ["md-microsoft_sharepoint"] = 0xf1391, + ["md-microsoft_teams"] = 0xf02bb, + ["md-microsoft_visual_studio"] = 0xf0610, + ["md-microsoft_visual_studio_code"] = 0xf0a1e, + ["md-microsoft_windows"] = 0xf05b3, + ["md-microsoft_windows_classic"] = 0xf0a21, + ["md-microsoft_word"] = 0xf1392, + ["md-microsoft_xbox"] = 0xf05b9, + ["md-microsoft_xbox_controller"] = 0xf05ba, + ["md-microsoft_xbox_controller_battery_alert"] = 0xf074b, + ["md-microsoft_xbox_controller_battery_charging"] = 0xf0a22, + ["md-microsoft_xbox_controller_battery_empty"] = 0xf074c, + ["md-microsoft_xbox_controller_battery_full"] = 0xf074d, + ["md-microsoft_xbox_controller_battery_low"] = 0xf074e, + ["md-microsoft_xbox_controller_battery_medium"] = 0xf074f, + ["md-microsoft_xbox_controller_battery_unknown"] = 0xf0750, + ["md-microsoft_xbox_controller_menu"] = 0xf0e6f, + ["md-microsoft_xbox_controller_off"] = 0xf05bb, + ["md-microsoft_xbox_controller_view"] = 0xf0e70, + ["md-microwave"] = 0xf0c99, + ["md-microwave_off"] = 0xf1423, + ["md-middleware"] = 0xf0f5d, + ["md-middleware_outline"] = 0xf0f5e, + ["md-midi"] = 0xf08f1, + ["md-midi_port"] = 0xf08f2, + ["md-mine"] = 0xf0dda, + ["md-minecraft"] = 0xf0373, + ["md-mini_sd"] = 0xf0a05, + ["md-minidisc"] = 0xf0a06, + ["md-minus"] = 0xf0374, + ["md-minus_box"] = 0xf0375, + ["md-minus_box_multiple"] = 0xf1141, + ["md-minus_box_multiple_outline"] = 0xf1142, + ["md-minus_box_outline"] = 0xf06f2, + ["md-minus_circle"] = 0xf0376, + ["md-minus_circle_multiple"] = 0xf035a, + ["md-minus_circle_multiple_outline"] = 0xf0ad3, + ["md-minus_circle_off"] = 0xf1459, + ["md-minus_circle_off_outline"] = 0xf145a, + ["md-minus_circle_outline"] = 0xf0377, + ["md-minus_network"] = 0xf0378, + ["md-minus_network_outline"] = 0xf0c9a, + ["md-minus_thick"] = 0xf1639, + ["md-mirror"] = 0xf11fd, + ["md-mirror_rectangle"] = 0xf179f, + ["md-mirror_variant"] = 0xf17a0, + ["md-mixed_martial_arts"] = 0xf0d8f, + ["md-mixed_reality"] = 0xf087f, + ["md-molecule"] = 0xf0bac, + ["md-molecule_co"] = 0xf12fe, + ["md-molecule_co2"] = 0xf07e4, + ["md-monitor"] = 0xf0379, + ["md-monitor_account"] = 0xf1a5b, + ["md-monitor_arrow_down"] = 0xf19d0, + ["md-monitor_arrow_down_variant"] = 0xf19d1, + ["md-monitor_cellphone"] = 0xf0989, + ["md-monitor_cellphone_star"] = 0xf098a, + ["md-monitor_dashboard"] = 0xf0a07, + ["md-monitor_edit"] = 0xf12c6, + ["md-monitor_eye"] = 0xf13b4, + ["md-monitor_lock"] = 0xf0ddb, + ["md-monitor_multiple"] = 0xf037a, + ["md-monitor_off"] = 0xf0d90, + ["md-monitor_screenshot"] = 0xf0e51, + ["md-monitor_share"] = 0xf1483, + ["md-monitor_shimmer"] = 0xf1104, + ["md-monitor_small"] = 0xf1876, + ["md-monitor_speaker"] = 0xf0f5f, + ["md-monitor_speaker_off"] = 0xf0f60, + ["md-monitor_star"] = 0xf0ddc, + ["md-moon_first_quarter"] = 0xf0f61, + ["md-moon_full"] = 0xf0f62, + ["md-moon_last_quarter"] = 0xf0f63, + ["md-moon_new"] = 0xf0f64, + ["md-moon_waning_crescent"] = 0xf0f65, + ["md-moon_waning_gibbous"] = 0xf0f66, + ["md-moon_waxing_crescent"] = 0xf0f67, + ["md-moon_waxing_gibbous"] = 0xf0f68, + ["md-moped"] = 0xf1086, + ["md-moped_electric"] = 0xf15b7, + ["md-moped_electric_outline"] = 0xf15b8, + ["md-moped_outline"] = 0xf15b9, + ["md-more"] = 0xf037b, + ["md-mortar_pestle"] = 0xf1748, + ["md-mortar_pestle_plus"] = 0xf03f1, + ["md-mosque"] = 0xf1827, + ["md-mother_heart"] = 0xf1314, + ["md-mother_nurse"] = 0xf0d21, + ["md-motion"] = 0xf15b2, + ["md-motion_outline"] = 0xf15b3, + ["md-motion_pause"] = 0xf1590, + ["md-motion_pause_outline"] = 0xf1592, + ["md-motion_play"] = 0xf158f, + ["md-motion_play_outline"] = 0xf1591, + ["md-motion_sensor"] = 0xf0d91, + ["md-motion_sensor_off"] = 0xf1435, + ["md-motorbike"] = 0xf037c, + ["md-motorbike_electric"] = 0xf15ba, + ["md-mouse"] = 0xf037d, + ["md-mouse_bluetooth"] = 0xf098b, + ["md-mouse_move_down"] = 0xf1550, + ["md-mouse_move_up"] = 0xf1551, + ["md-mouse_move_vertical"] = 0xf1552, + ["md-mouse_off"] = 0xf037e, + ["md-mouse_variant"] = 0xf037f, + ["md-mouse_variant_off"] = 0xf0380, + ["md-move_resize"] = 0xf0655, + ["md-move_resize_variant"] = 0xf0656, + ["md-movie"] = 0xf0381, + ["md-movie_check"] = 0xf16f3, + ["md-movie_check_outline"] = 0xf16f4, + ["md-movie_cog"] = 0xf16f5, + ["md-movie_cog_outline"] = 0xf16f6, + ["md-movie_edit"] = 0xf1122, + ["md-movie_edit_outline"] = 0xf1123, + ["md-movie_filter"] = 0xf1124, + ["md-movie_filter_outline"] = 0xf1125, + ["md-movie_minus"] = 0xf16f7, + ["md-movie_minus_outline"] = 0xf16f8, + ["md-movie_off"] = 0xf16f9, + ["md-movie_off_outline"] = 0xf16fa, + ["md-movie_open"] = 0xf0fce, + ["md-movie_open_check"] = 0xf16fb, + ["md-movie_open_check_outline"] = 0xf16fc, + ["md-movie_open_cog"] = 0xf16fd, + ["md-movie_open_cog_outline"] = 0xf16fe, + ["md-movie_open_edit"] = 0xf16ff, + ["md-movie_open_edit_outline"] = 0xf1700, + ["md-movie_open_minus"] = 0xf1701, + ["md-movie_open_minus_outline"] = 0xf1702, + ["md-movie_open_off"] = 0xf1703, + ["md-movie_open_off_outline"] = 0xf1704, + ["md-movie_open_outline"] = 0xf0fcf, + ["md-movie_open_play"] = 0xf1705, + ["md-movie_open_play_outline"] = 0xf1706, + ["md-movie_open_plus"] = 0xf1707, + ["md-movie_open_plus_outline"] = 0xf1708, + ["md-movie_open_remove"] = 0xf1709, + ["md-movie_open_remove_outline"] = 0xf170a, + ["md-movie_open_settings"] = 0xf170b, + ["md-movie_open_settings_outline"] = 0xf170c, + ["md-movie_open_star"] = 0xf170d, + ["md-movie_open_star_outline"] = 0xf170e, + ["md-movie_outline"] = 0xf0ddd, + ["md-movie_play"] = 0xf170f, + ["md-movie_play_outline"] = 0xf1710, + ["md-movie_plus"] = 0xf1711, + ["md-movie_plus_outline"] = 0xf1712, + ["md-movie_remove"] = 0xf1713, + ["md-movie_remove_outline"] = 0xf1714, + ["md-movie_roll"] = 0xf07de, + ["md-movie_search"] = 0xf11d2, + ["md-movie_search_outline"] = 0xf11d3, + ["md-movie_settings"] = 0xf1715, + ["md-movie_settings_outline"] = 0xf1716, + ["md-movie_star"] = 0xf1717, + ["md-movie_star_outline"] = 0xf1718, + ["md-mower"] = 0xf166f, + ["md-mower_bag"] = 0xf1670, + ["md-muffin"] = 0xf098c, + ["md-multicast"] = 0xf1893, + ["md-multiplication"] = 0xf0382, + ["md-multiplication_box"] = 0xf0383, + ["md-mushroom"] = 0xf07df, + ["md-mushroom_off"] = 0xf13fa, + ["md-mushroom_off_outline"] = 0xf13fb, + ["md-mushroom_outline"] = 0xf07e0, + ["md-music"] = 0xf075a, + ["md-music_accidental_double_flat"] = 0xf0f69, + ["md-music_accidental_double_sharp"] = 0xf0f6a, + ["md-music_accidental_flat"] = 0xf0f6b, + ["md-music_accidental_natural"] = 0xf0f6c, + ["md-music_accidental_sharp"] = 0xf0f6d, + ["md-music_box"] = 0xf0384, + ["md-music_box_multiple"] = 0xf0333, + ["md-music_box_multiple_outline"] = 0xf0f04, + ["md-music_box_outline"] = 0xf0385, + ["md-music_circle"] = 0xf0386, + ["md-music_circle_outline"] = 0xf0ad4, + ["md-music_clef_alto"] = 0xf0f6e, + ["md-music_clef_bass"] = 0xf0f6f, + ["md-music_clef_treble"] = 0xf0f70, + ["md-music_note"] = 0xf0388, + ["md-music_note_bluetooth"] = 0xf05fe, + ["md-music_note_bluetooth_off"] = 0xf05ff, + ["md-music_note_eighth_dotted"] = 0xf0f71, + ["md-music_note_half"] = 0xf0389, + ["md-music_note_half_dotted"] = 0xf0f72, + ["md-music_note_off"] = 0xf038a, + ["md-music_note_off_outline"] = 0xf0f73, + ["md-music_note_outline"] = 0xf0f74, + ["md-music_note_plus"] = 0xf0dde, + ["md-music_note_quarter"] = 0xf038b, + ["md-music_note_quarter_dotted"] = 0xf0f75, + ["md-music_note_sixteenth"] = 0xf038c, + ["md-music_note_sixteenth_dotted"] = 0xf0f76, + ["md-music_note_whole"] = 0xf038d, + ["md-music_note_whole_dotted"] = 0xf0f77, + ["md-music_off"] = 0xf075b, + ["md-music_rest_eighth"] = 0xf0f78, + ["md-music_rest_half"] = 0xf0f79, + ["md-music_rest_quarter"] = 0xf0f7a, + ["md-music_rest_sixteenth"] = 0xf0f7b, + ["md-music_rest_whole"] = 0xf0f7c, + ["md-mustache"] = 0xf15de, + ["md-nail"] = 0xf0ddf, + ["md-nas"] = 0xf08f3, + ["md-nativescript"] = 0xf0880, + ["md-nature"] = 0xf038e, + ["md-nature_people"] = 0xf038f, + ["md-navigation"] = 0xf0390, + ["md-navigation_outline"] = 0xf1607, + ["md-navigation_variant_outline"] = 0xf18f1, + ["md-near_me"] = 0xf18f0, + ["md-necklace"] = 0xf0f0b, + ["md-needle"] = 0xf0391, + ["md-needle_off"] = 0xf19d2, + ["md-netflix"] = 0xf0746, + ["md-network"] = 0xf06f3, + ["md-network_off"] = 0xf0c9b, + ["md-network_off_outline"] = 0xf0c9c, + ["md-network_outline"] = 0xf0c9d, + ["md-network_pos"] = 0xf1acb, + ["md-network_strength_1"] = 0xf08f4, + ["md-network_strength_1_alert"] = 0xf08f5, + ["md-network_strength_2"] = 0xf08f6, + ["md-network_strength_2_alert"] = 0xf08f7, + ["md-network_strength_3"] = 0xf08f8, + ["md-network_strength_3_alert"] = 0xf08f9, + ["md-network_strength_4"] = 0xf08fa, + ["md-network_strength_4_alert"] = 0xf08fb, + ["md-network_strength_4_cog"] = 0xf191a, + ["md-network_strength_off"] = 0xf08fc, + ["md-network_strength_off_outline"] = 0xf08fd, + ["md-network_strength_outline"] = 0xf08fe, + ["md-new_box"] = 0xf0394, + ["md-newspaper"] = 0xf0395, + ["md-newspaper_check"] = 0xf1943, + ["md-newspaper_minus"] = 0xf0f0c, + ["md-newspaper_plus"] = 0xf0f0d, + ["md-newspaper_remove"] = 0xf1944, + ["md-newspaper_variant"] = 0xf1001, + ["md-newspaper_variant_multiple"] = 0xf1002, + ["md-newspaper_variant_multiple_outline"] = 0xf1003, + ["md-newspaper_variant_outline"] = 0xf1004, + ["md-nfc"] = 0xf0396, + ["md-nfc_search_variant"] = 0xf0e53, + ["md-nfc_tap"] = 0xf0397, + ["md-nfc_variant"] = 0xf0398, + ["md-nfc_variant_off"] = 0xf0e54, + ["md-ninja"] = 0xf0774, + ["md-nintendo_game_boy"] = 0xf1393, + ["md-nintendo_switch"] = 0xf07e1, + ["md-nintendo_wii"] = 0xf05ab, + ["md-nintendo_wiiu"] = 0xf072d, + ["md-nix"] = 0xf1105, + ["md-nodejs"] = 0xf0399, + ["md-noodles"] = 0xf117e, + ["md-not_equal"] = 0xf098d, + ["md-not_equal_variant"] = 0xf098e, + ["md-note"] = 0xf039a, + ["md-note_alert"] = 0xf177d, + ["md-note_alert_outline"] = 0xf177e, + ["md-note_check"] = 0xf177f, + ["md-note_check_outline"] = 0xf1780, + ["md-note_edit"] = 0xf1781, + ["md-note_edit_outline"] = 0xf1782, + ["md-note_minus"] = 0xf164f, + ["md-note_minus_outline"] = 0xf1650, + ["md-note_multiple"] = 0xf06b8, + ["md-note_multiple_outline"] = 0xf06b9, + ["md-note_off"] = 0xf1783, + ["md-note_off_outline"] = 0xf1784, + ["md-note_outline"] = 0xf039b, + ["md-note_plus"] = 0xf039c, + ["md-note_plus_outline"] = 0xf039d, + ["md-note_remove"] = 0xf1651, + ["md-note_remove_outline"] = 0xf1652, + ["md-note_search"] = 0xf1653, + ["md-note_search_outline"] = 0xf1654, + ["md-note_text"] = 0xf039e, + ["md-note_text_outline"] = 0xf11d7, + ["md-notebook"] = 0xf082e, + ["md-notebook_check"] = 0xf14f5, + ["md-notebook_check_outline"] = 0xf14f6, + ["md-notebook_edit"] = 0xf14e7, + ["md-notebook_edit_outline"] = 0xf14e9, + ["md-notebook_heart"] = 0xf1a0b, + ["md-notebook_heart_outline"] = 0xf1a0c, + ["md-notebook_minus"] = 0xf1610, + ["md-notebook_minus_outline"] = 0xf1611, + ["md-notebook_multiple"] = 0xf0e55, + ["md-notebook_outline"] = 0xf0ebf, + ["md-notebook_plus"] = 0xf1612, + ["md-notebook_plus_outline"] = 0xf1613, + ["md-notebook_remove"] = 0xf1614, + ["md-notebook_remove_outline"] = 0xf1615, + ["md-notification_clear_all"] = 0xf039f, + ["md-npm"] = 0xf06f7, + ["md-nuke"] = 0xf06a4, + ["md-null"] = 0xf07e2, + ["md-numeric"] = 0xf03a0, + ["md-numeric_0_box"] = 0xf03a1, + ["md-numeric_0_box_multiple"] = 0xf0f0e, + ["md-numeric_0_box_multiple_outline"] = 0xf03a2, + ["md-numeric_0_box_outline"] = 0xf03a3, + ["md-numeric_1"] = 0xf0b3a, + ["md-numeric_10"] = 0xf0fe9, + ["md-numeric_10_box"] = 0xf0f7d, + ["md-numeric_10_box_multiple"] = 0xf0fea, + ["md-numeric_10_box_multiple_outline"] = 0xf0feb, + ["md-numeric_10_box_outline"] = 0xf0f7e, + ["md-numeric_10_circle"] = 0xf0fec, + ["md-numeric_10_circle_outline"] = 0xf0fed, + ["md-numeric_1_box"] = 0xf03a4, + ["md-numeric_1_box_multiple"] = 0xf0f0f, + ["md-numeric_1_box_multiple_outline"] = 0xf03a5, + ["md-numeric_1_box_outline"] = 0xf03a6, + ["md-numeric_1_circle"] = 0xf0ca0, + ["md-numeric_1_circle_outline"] = 0xf0ca1, + ["md-numeric_2"] = 0xf0b3b, + ["md-numeric_2_box"] = 0xf03a7, + ["md-numeric_2_box_multiple"] = 0xf0f10, + ["md-numeric_2_box_multiple_outline"] = 0xf03a8, + ["md-numeric_2_box_outline"] = 0xf03a9, + ["md-numeric_2_circle"] = 0xf0ca2, + ["md-numeric_2_circle_outline"] = 0xf0ca3, + ["md-numeric_3"] = 0xf0b3c, + ["md-numeric_3_box"] = 0xf03aa, + ["md-numeric_3_box_multiple"] = 0xf0f11, + ["md-numeric_3_box_multiple_outline"] = 0xf03ab, + ["md-numeric_3_box_outline"] = 0xf03ac, + ["md-numeric_3_circle"] = 0xf0ca4, + ["md-numeric_3_circle_outline"] = 0xf0ca5, + ["md-numeric_4"] = 0xf0b3d, + ["md-numeric_4_box"] = 0xf03ad, + ["md-numeric_4_box_multiple"] = 0xf0f12, + ["md-numeric_4_box_multiple_outline"] = 0xf03b2, + ["md-numeric_4_box_outline"] = 0xf03ae, + ["md-numeric_4_circle"] = 0xf0ca6, + ["md-numeric_4_circle_outline"] = 0xf0ca7, + ["md-numeric_5"] = 0xf0b3e, + ["md-numeric_5_box"] = 0xf03b1, + ["md-numeric_5_box_multiple"] = 0xf0f13, + ["md-numeric_5_box_multiple_outline"] = 0xf03af, + ["md-numeric_5_box_outline"] = 0xf03b0, + ["md-numeric_5_circle"] = 0xf0ca8, + ["md-numeric_5_circle_outline"] = 0xf0ca9, + ["md-numeric_6"] = 0xf0b3f, + ["md-numeric_6_box"] = 0xf03b3, + ["md-numeric_6_box_multiple"] = 0xf0f14, + ["md-numeric_6_box_multiple_outline"] = 0xf03b4, + ["md-numeric_6_box_outline"] = 0xf03b5, + ["md-numeric_6_circle"] = 0xf0caa, + ["md-numeric_6_circle_outline"] = 0xf0cab, + ["md-numeric_7"] = 0xf0b40, + ["md-numeric_7_box"] = 0xf03b6, + ["md-numeric_7_box_multiple"] = 0xf0f15, + ["md-numeric_7_box_multiple_outline"] = 0xf03b7, + ["md-numeric_7_box_outline"] = 0xf03b8, + ["md-numeric_7_circle"] = 0xf0cac, + ["md-numeric_7_circle_outline"] = 0xf0cad, + ["md-numeric_8"] = 0xf0b41, + ["md-numeric_8_box"] = 0xf03b9, + ["md-numeric_8_box_multiple"] = 0xf0f16, + ["md-numeric_8_box_multiple_outline"] = 0xf03ba, + ["md-numeric_8_box_outline"] = 0xf03bb, + ["md-numeric_8_circle"] = 0xf0cae, + ["md-numeric_8_circle_outline"] = 0xf0caf, + ["md-numeric_9"] = 0xf0b42, + ["md-numeric_9_box"] = 0xf03bc, + ["md-numeric_9_box_multiple"] = 0xf0f17, + ["md-numeric_9_box_multiple_outline"] = 0xf03bd, + ["md-numeric_9_box_outline"] = 0xf03be, + ["md-numeric_9_circle"] = 0xf0cb0, + ["md-numeric_9_circle_outline"] = 0xf0cb1, + ["md-numeric_9_plus"] = 0xf0fee, + ["md-numeric_9_plus_box"] = 0xf03bf, + ["md-numeric_9_plus_box_multiple"] = 0xf0f18, + ["md-numeric_9_plus_box_multiple_outline"] = 0xf03c0, + ["md-numeric_9_plus_box_outline"] = 0xf03c1, + ["md-numeric_9_plus_circle"] = 0xf0cb2, + ["md-numeric_9_plus_circle_outline"] = 0xf0cb3, + ["md-numeric_negative_1"] = 0xf1052, + ["md-numeric_off"] = 0xf19d3, + ["md-numeric_positive_1"] = 0xf15cb, + ["md-nut"] = 0xf06f8, + ["md-nutrition"] = 0xf03c2, + ["md-nuxt"] = 0xf1106, + ["md-oar"] = 0xf067c, + ["md-ocarina"] = 0xf0de0, + ["md-oci"] = 0xf12e9, + ["md-ocr"] = 0xf113a, + ["md-octagon"] = 0xf03c3, + ["md-octagon_outline"] = 0xf03c4, + ["md-octagram"] = 0xf06f9, + ["md-octagram_outline"] = 0xf0775, + ["md-octahedron"] = 0xf1950, + ["md-octahedron_off"] = 0xf1951, + ["md-odnoklassniki"] = 0xf03c5, + ["md-offer"] = 0xf121b, + ["md-office_building"] = 0xf0991, + ["md-office_building_cog"] = 0xf1949, + ["md-office_building_cog_outline"] = 0xf194a, + ["md-office_building_marker"] = 0xf1520, + ["md-office_building_marker_outline"] = 0xf1521, + ["md-office_building_outline"] = 0xf151f, + ["md-oil"] = 0xf03c7, + ["md-oil_lamp"] = 0xf0f19, + ["md-oil_level"] = 0xf1053, + ["md-oil_temperature"] = 0xf0ff8, + ["md-om"] = 0xf0973, + ["md-omega"] = 0xf03c9, + ["md-one_up"] = 0xf0bad, + ["md-onepassword"] = 0xf0881, + ["md-opacity"] = 0xf05cc, + ["md-open_in_app"] = 0xf03cb, + ["md-open_in_new"] = 0xf03cc, + ["md-open_source_initiative"] = 0xf0bae, + ["md-openid"] = 0xf03cd, + ["md-opera"] = 0xf03ce, + ["md-orbit"] = 0xf0018, + ["md-orbit_variant"] = 0xf15db, + ["md-order_alphabetical_ascending"] = 0xf020d, + ["md-order_alphabetical_descending"] = 0xf0d07, + ["md-order_bool_ascending"] = 0xf02be, + ["md-order_bool_ascending_variant"] = 0xf098f, + ["md-order_bool_descending"] = 0xf1384, + ["md-order_bool_descending_variant"] = 0xf0990, + ["md-order_numeric_ascending"] = 0xf0545, + ["md-order_numeric_descending"] = 0xf0546, + ["md-origin"] = 0xf0b43, + ["md-ornament"] = 0xf03cf, + ["md-ornament_variant"] = 0xf03d0, + ["md-outdoor_lamp"] = 0xf1054, + ["md-overscan"] = 0xf1005, + ["md-owl"] = 0xf03d2, + ["md-pac_man"] = 0xf0baf, + ["md-package"] = 0xf03d3, + ["md-package_down"] = 0xf03d4, + ["md-package_up"] = 0xf03d5, + ["md-package_variant"] = 0xf03d6, + ["md-package_variant_closed"] = 0xf03d7, + ["md-package_variant_closed_minus"] = 0xf19d4, + ["md-package_variant_closed_plus"] = 0xf19d5, + ["md-package_variant_closed_remove"] = 0xf19d6, + ["md-package_variant_minus"] = 0xf19d7, + ["md-package_variant_plus"] = 0xf19d8, + ["md-package_variant_remove"] = 0xf19d9, + ["md-page_first"] = 0xf0600, + ["md-page_last"] = 0xf0601, + ["md-page_layout_body"] = 0xf06fa, + ["md-page_layout_footer"] = 0xf06fb, + ["md-page_layout_header"] = 0xf06fc, + ["md-page_layout_header_footer"] = 0xf0f7f, + ["md-page_layout_sidebar_left"] = 0xf06fd, + ["md-page_layout_sidebar_right"] = 0xf06fe, + ["md-page_next"] = 0xf0bb0, + ["md-page_next_outline"] = 0xf0bb1, + ["md-page_previous"] = 0xf0bb2, + ["md-page_previous_outline"] = 0xf0bb3, + ["md-pail"] = 0xf1417, + ["md-pail_minus"] = 0xf1437, + ["md-pail_minus_outline"] = 0xf143c, + ["md-pail_off"] = 0xf1439, + ["md-pail_off_outline"] = 0xf143e, + ["md-pail_outline"] = 0xf143a, + ["md-pail_plus"] = 0xf1436, + ["md-pail_plus_outline"] = 0xf143b, + ["md-pail_remove"] = 0xf1438, + ["md-pail_remove_outline"] = 0xf143d, + ["md-palette"] = 0xf03d8, + ["md-palette_advanced"] = 0xf03d9, + ["md-palette_outline"] = 0xf0e0c, + ["md-palette_swatch"] = 0xf08b5, + ["md-palette_swatch_outline"] = 0xf135c, + ["md-palette_swatch_variant"] = 0xf195a, + ["md-palm_tree"] = 0xf1055, + ["md-pan"] = 0xf0bb4, + ["md-pan_bottom_left"] = 0xf0bb5, + ["md-pan_bottom_right"] = 0xf0bb6, + ["md-pan_down"] = 0xf0bb7, + ["md-pan_horizontal"] = 0xf0bb8, + ["md-pan_left"] = 0xf0bb9, + ["md-pan_right"] = 0xf0bba, + ["md-pan_top_left"] = 0xf0bbb, + ["md-pan_top_right"] = 0xf0bbc, + ["md-pan_up"] = 0xf0bbd, + ["md-pan_vertical"] = 0xf0bbe, + ["md-panda"] = 0xf03da, + ["md-pandora"] = 0xf03db, + ["md-panorama"] = 0xf03dc, + ["md-panorama_fisheye"] = 0xf03dd, + ["md-panorama_horizontal"] = 0xf1928, + ["md-panorama_horizontal_outline"] = 0xf03de, + ["md-panorama_outline"] = 0xf198c, + ["md-panorama_sphere"] = 0xf198d, + ["md-panorama_sphere_outline"] = 0xf198e, + ["md-panorama_variant"] = 0xf198f, + ["md-panorama_variant_outline"] = 0xf1990, + ["md-panorama_vertical"] = 0xf1929, + ["md-panorama_vertical_outline"] = 0xf03df, + ["md-panorama_wide_angle"] = 0xf195f, + ["md-panorama_wide_angle_outline"] = 0xf03e0, + ["md-paper_cut_vertical"] = 0xf03e1, + ["md-paper_roll"] = 0xf1157, + ["md-paper_roll_outline"] = 0xf1158, + ["md-paperclip"] = 0xf03e2, + ["md-paperclip_check"] = 0xf1ac6, + ["md-paperclip_lock"] = 0xf19da, + ["md-paperclip_minus"] = 0xf1ac7, + ["md-paperclip_off"] = 0xf1ac8, + ["md-paperclip_plus"] = 0xf1ac9, + ["md-paperclip_remove"] = 0xf1aca, + ["md-parachute"] = 0xf0cb4, + ["md-parachute_outline"] = 0xf0cb5, + ["md-paragliding"] = 0xf1745, + ["md-parking"] = 0xf03e3, + ["md-party_popper"] = 0xf1056, + ["md-passport"] = 0xf07e3, + ["md-passport_biometric"] = 0xf0de1, + ["md-pasta"] = 0xf1160, + ["md-patio_heater"] = 0xf0f80, + ["md-patreon"] = 0xf0882, + ["md-pause"] = 0xf03e4, + ["md-pause_circle"] = 0xf03e5, + ["md-pause_circle_outline"] = 0xf03e6, + ["md-pause_octagon"] = 0xf03e7, + ["md-pause_octagon_outline"] = 0xf03e8, + ["md-paw"] = 0xf03e9, + ["md-paw_off"] = 0xf0657, + ["md-paw_off_outline"] = 0xf1676, + ["md-paw_outline"] = 0xf1675, + ["md-peace"] = 0xf0884, + ["md-peanut"] = 0xf0ffc, + ["md-peanut_off"] = 0xf0ffd, + ["md-peanut_off_outline"] = 0xf0fff, + ["md-peanut_outline"] = 0xf0ffe, + ["md-pen"] = 0xf03ea, + ["md-pen_lock"] = 0xf0de2, + ["md-pen_minus"] = 0xf0de3, + ["md-pen_off"] = 0xf0de4, + ["md-pen_plus"] = 0xf0de5, + ["md-pen_remove"] = 0xf0de6, + ["md-pencil"] = 0xf03eb, + ["md-pencil_box"] = 0xf03ec, + ["md-pencil_box_multiple"] = 0xf1144, + ["md-pencil_box_multiple_outline"] = 0xf1145, + ["md-pencil_box_outline"] = 0xf03ed, + ["md-pencil_circle"] = 0xf06ff, + ["md-pencil_circle_outline"] = 0xf0776, + ["md-pencil_lock"] = 0xf03ee, + ["md-pencil_lock_outline"] = 0xf0de7, + ["md-pencil_minus"] = 0xf0de8, + ["md-pencil_minus_outline"] = 0xf0de9, + ["md-pencil_off"] = 0xf03ef, + ["md-pencil_off_outline"] = 0xf0dea, + ["md-pencil_outline"] = 0xf0cb6, + ["md-pencil_plus"] = 0xf0deb, + ["md-pencil_plus_outline"] = 0xf0dec, + ["md-pencil_remove"] = 0xf0ded, + ["md-pencil_remove_outline"] = 0xf0dee, + ["md-pencil_ruler"] = 0xf1353, + ["md-penguin"] = 0xf0ec0, + ["md-pentagon"] = 0xf0701, + ["md-pentagon_outline"] = 0xf0700, + ["md-pentagram"] = 0xf1667, + ["md-percent"] = 0xf03f0, + ["md-percent_box"] = 0xf1a02, + ["md-percent_box_outline"] = 0xf1a03, + ["md-percent_circle"] = 0xf1a04, + ["md-percent_circle_outline"] = 0xf1a05, + ["md-percent_outline"] = 0xf1278, + ["md-periodic_table"] = 0xf08b6, + ["md-perspective_less"] = 0xf0d23, + ["md-perspective_more"] = 0xf0d24, + ["md-ph"] = 0xf17c5, + ["md-phone"] = 0xf03f2, + ["md-phone_alert"] = 0xf0f1a, + ["md-phone_alert_outline"] = 0xf118e, + ["md-phone_bluetooth"] = 0xf03f3, + ["md-phone_bluetooth_outline"] = 0xf118f, + ["md-phone_cancel"] = 0xf10bc, + ["md-phone_cancel_outline"] = 0xf1190, + ["md-phone_check"] = 0xf11a9, + ["md-phone_check_outline"] = 0xf11aa, + ["md-phone_classic"] = 0xf0602, + ["md-phone_classic_off"] = 0xf1279, + ["md-phone_clock"] = 0xf19db, + ["md-phone_dial"] = 0xf1559, + ["md-phone_dial_outline"] = 0xf155a, + ["md-phone_forward"] = 0xf03f4, + ["md-phone_forward_outline"] = 0xf1191, + ["md-phone_hangup"] = 0xf03f5, + ["md-phone_hangup_outline"] = 0xf1192, + ["md-phone_in_talk"] = 0xf03f6, + ["md-phone_in_talk_outline"] = 0xf1182, + ["md-phone_incoming"] = 0xf03f7, + ["md-phone_incoming_outline"] = 0xf1193, + ["md-phone_lock"] = 0xf03f8, + ["md-phone_lock_outline"] = 0xf1194, + ["md-phone_log"] = 0xf03f9, + ["md-phone_log_outline"] = 0xf1195, + ["md-phone_message"] = 0xf1196, + ["md-phone_message_outline"] = 0xf1197, + ["md-phone_minus"] = 0xf0658, + ["md-phone_minus_outline"] = 0xf1198, + ["md-phone_missed"] = 0xf03fa, + ["md-phone_missed_outline"] = 0xf11a5, + ["md-phone_off"] = 0xf0def, + ["md-phone_off_outline"] = 0xf11a6, + ["md-phone_outgoing"] = 0xf03fb, + ["md-phone_outgoing_outline"] = 0xf1199, + ["md-phone_outline"] = 0xf0df0, + ["md-phone_paused"] = 0xf03fc, + ["md-phone_paused_outline"] = 0xf119a, + ["md-phone_plus"] = 0xf0659, + ["md-phone_plus_outline"] = 0xf119b, + ["md-phone_refresh"] = 0xf1993, + ["md-phone_refresh_outline"] = 0xf1994, + ["md-phone_remove"] = 0xf152f, + ["md-phone_remove_outline"] = 0xf1530, + ["md-phone_return"] = 0xf082f, + ["md-phone_return_outline"] = 0xf119c, + ["md-phone_ring"] = 0xf11ab, + ["md-phone_ring_outline"] = 0xf11ac, + ["md-phone_rotate_landscape"] = 0xf0885, + ["md-phone_rotate_portrait"] = 0xf0886, + ["md-phone_settings"] = 0xf03fd, + ["md-phone_settings_outline"] = 0xf119d, + ["md-phone_sync"] = 0xf1995, + ["md-phone_sync_outline"] = 0xf1996, + ["md-phone_voip"] = 0xf03fe, + ["md-pi"] = 0xf03ff, + ["md-pi_box"] = 0xf0400, + ["md-pi_hole"] = 0xf0df1, + ["md-piano"] = 0xf067d, + ["md-piano_off"] = 0xf0698, + ["md-pickaxe"] = 0xf08b7, + ["md-picture_in_picture_bottom_right"] = 0xf0e57, + ["md-picture_in_picture_bottom_right_outline"] = 0xf0e58, + ["md-picture_in_picture_top_right"] = 0xf0e59, + ["md-picture_in_picture_top_right_outline"] = 0xf0e5a, + ["md-pier"] = 0xf0887, + ["md-pier_crane"] = 0xf0888, + ["md-pig"] = 0xf0401, + ["md-pig_variant"] = 0xf1006, + ["md-pig_variant_outline"] = 0xf1678, + ["md-piggy_bank"] = 0xf1007, + ["md-piggy_bank_outline"] = 0xf1679, + ["md-pill"] = 0xf0402, + ["md-pill_off"] = 0xf1a5c, + ["md-pillar"] = 0xf0702, + ["md-pin"] = 0xf0403, + ["md-pin_off"] = 0xf0404, + ["md-pin_off_outline"] = 0xf0930, + ["md-pin_outline"] = 0xf0931, + ["md-pine_tree"] = 0xf0405, + ["md-pine_tree_box"] = 0xf0406, + ["md-pine_tree_fire"] = 0xf141a, + ["md-pinterest"] = 0xf0407, + ["md-pinwheel"] = 0xf0ad5, + ["md-pinwheel_outline"] = 0xf0ad6, + ["md-pipe"] = 0xf07e5, + ["md-pipe_disconnected"] = 0xf07e6, + ["md-pipe_leak"] = 0xf0889, + ["md-pipe_valve"] = 0xf184d, + ["md-pipe_wrench"] = 0xf1354, + ["md-pirate"] = 0xf0a08, + ["md-pistol"] = 0xf0703, + ["md-piston"] = 0xf088a, + ["md-pitchfork"] = 0xf1553, + ["md-pizza"] = 0xf0409, + ["md-play"] = 0xf040a, + ["md-play_box"] = 0xf127a, + ["md-play_box_lock"] = 0xf1a16, + ["md-play_box_lock_open"] = 0xf1a17, + ["md-play_box_lock_open_outline"] = 0xf1a18, + ["md-play_box_lock_outline"] = 0xf1a19, + ["md-play_box_multiple"] = 0xf0d19, + ["md-play_box_multiple_outline"] = 0xf13e6, + ["md-play_box_outline"] = 0xf040b, + ["md-play_circle"] = 0xf040c, + ["md-play_circle_outline"] = 0xf040d, + ["md-play_network"] = 0xf088b, + ["md-play_network_outline"] = 0xf0cb7, + ["md-play_outline"] = 0xf0f1b, + ["md-play_pause"] = 0xf040e, + ["md-play_protected_content"] = 0xf040f, + ["md-play_speed"] = 0xf08ff, + ["md-playlist_check"] = 0xf05c7, + ["md-playlist_edit"] = 0xf0900, + ["md-playlist_minus"] = 0xf0410, + ["md-playlist_music"] = 0xf0cb8, + ["md-playlist_music_outline"] = 0xf0cb9, + ["md-playlist_play"] = 0xf0411, + ["md-playlist_plus"] = 0xf0412, + ["md-playlist_remove"] = 0xf0413, + ["md-playlist_star"] = 0xf0df2, + ["md-plex"] = 0xf06ba, + ["md-pliers"] = 0xf19a4, + ["md-plus"] = 0xf0415, + ["md-plus_box"] = 0xf0416, + ["md-plus_box_multiple"] = 0xf0334, + ["md-plus_box_multiple_outline"] = 0xf1143, + ["md-plus_box_outline"] = 0xf0704, + ["md-plus_circle"] = 0xf0417, + ["md-plus_circle_multiple"] = 0xf034c, + ["md-plus_circle_multiple_outline"] = 0xf0418, + ["md-plus_circle_outline"] = 0xf0419, + ["md-plus_lock"] = 0xf1a5d, + ["md-plus_lock_open"] = 0xf1a5e, + ["md-plus_minus"] = 0xf0992, + ["md-plus_minus_box"] = 0xf0993, + ["md-plus_minus_variant"] = 0xf14c9, + ["md-plus_network"] = 0xf041a, + ["md-plus_network_outline"] = 0xf0cba, + ["md-plus_outline"] = 0xf0705, + ["md-plus_thick"] = 0xf11ec, + ["md-podcast"] = 0xf0994, + ["md-podium"] = 0xf0d25, + ["md-podium_bronze"] = 0xf0d26, + ["md-podium_gold"] = 0xf0d27, + ["md-podium_silver"] = 0xf0d28, + ["md-point_of_sale"] = 0xf0d92, + ["md-pokeball"] = 0xf041d, + ["md-pokemon_go"] = 0xf0a09, + ["md-poker_chip"] = 0xf0830, + ["md-polaroid"] = 0xf041e, + ["md-police_badge"] = 0xf1167, + ["md-police_badge_outline"] = 0xf1168, + ["md-police_station"] = 0xf1839, + ["md-poll"] = 0xf041f, + ["md-polo"] = 0xf14c3, + ["md-polymer"] = 0xf0421, + ["md-pool"] = 0xf0606, + ["md-pool_thermometer"] = 0xf1a5f, + ["md-popcorn"] = 0xf0422, + ["md-post"] = 0xf1008, + ["md-post_lamp"] = 0xf1a60, + ["md-post_outline"] = 0xf1009, + ["md-postage_stamp"] = 0xf0cbb, + ["md-pot"] = 0xf02e5, + ["md-pot_mix"] = 0xf065b, + ["md-pot_mix_outline"] = 0xf0677, + ["md-pot_outline"] = 0xf02ff, + ["md-pot_steam"] = 0xf065a, + ["md-pot_steam_outline"] = 0xf0326, + ["md-pound"] = 0xf0423, + ["md-pound_box"] = 0xf0424, + ["md-pound_box_outline"] = 0xf117f, + ["md-power"] = 0xf0425, + ["md-power_cycle"] = 0xf0901, + ["md-power_off"] = 0xf0902, + ["md-power_on"] = 0xf0903, + ["md-power_plug"] = 0xf06a5, + ["md-power_plug_off"] = 0xf06a6, + ["md-power_plug_off_outline"] = 0xf1424, + ["md-power_plug_outline"] = 0xf1425, + ["md-power_settings"] = 0xf0426, + ["md-power_sleep"] = 0xf0904, + ["md-power_socket"] = 0xf0427, + ["md-power_socket_au"] = 0xf0905, + ["md-power_socket_ch"] = 0xf0fb3, + ["md-power_socket_de"] = 0xf1107, + ["md-power_socket_eu"] = 0xf07e7, + ["md-power_socket_fr"] = 0xf1108, + ["md-power_socket_it"] = 0xf14ff, + ["md-power_socket_jp"] = 0xf1109, + ["md-power_socket_uk"] = 0xf07e8, + ["md-power_socket_us"] = 0xf07e9, + ["md-power_standby"] = 0xf0906, + ["md-powershell"] = 0xf0a0a, + ["md-prescription"] = 0xf0706, + ["md-presentation"] = 0xf0428, + ["md-presentation_play"] = 0xf0429, + ["md-pretzel"] = 0xf1562, + ["md-printer"] = 0xf042a, + ["md-printer_3d"] = 0xf042b, + ["md-printer_3d_nozzle"] = 0xf0e5b, + ["md-printer_3d_nozzle_alert"] = 0xf11c0, + ["md-printer_3d_nozzle_alert_outline"] = 0xf11c1, + ["md-printer_3d_nozzle_heat"] = 0xf18b8, + ["md-printer_3d_nozzle_heat_outline"] = 0xf18b9, + ["md-printer_3d_nozzle_outline"] = 0xf0e5c, + ["md-printer_alert"] = 0xf042c, + ["md-printer_check"] = 0xf1146, + ["md-printer_eye"] = 0xf1458, + ["md-printer_off"] = 0xf0e5d, + ["md-printer_off_outline"] = 0xf1785, + ["md-printer_outline"] = 0xf1786, + ["md-printer_pos"] = 0xf1057, + ["md-printer_search"] = 0xf1457, + ["md-printer_settings"] = 0xf0707, + ["md-printer_wireless"] = 0xf0a0b, + ["md-priority_high"] = 0xf0603, + ["md-priority_low"] = 0xf0604, + ["md-professional_hexagon"] = 0xf042d, + ["md-progress_alert"] = 0xf0cbc, + ["md-progress_check"] = 0xf0995, + ["md-progress_clock"] = 0xf0996, + ["md-progress_close"] = 0xf110a, + ["md-progress_download"] = 0xf0997, + ["md-progress_pencil"] = 0xf1787, + ["md-progress_question"] = 0xf1522, + ["md-progress_star"] = 0xf1788, + ["md-progress_upload"] = 0xf0998, + ["md-progress_wrench"] = 0xf0cbd, + ["md-projector"] = 0xf042e, + ["md-projector_off"] = 0xf1a23, + ["md-projector_screen"] = 0xf042f, + ["md-projector_screen_off"] = 0xf180d, + ["md-projector_screen_off_outline"] = 0xf180e, + ["md-projector_screen_outline"] = 0xf1724, + ["md-projector_screen_variant"] = 0xf180f, + ["md-projector_screen_variant_off"] = 0xf1810, + ["md-projector_screen_variant_off_outline"] = 0xf1811, + ["md-projector_screen_variant_outline"] = 0xf1812, + ["md-propane_tank"] = 0xf1357, + ["md-propane_tank_outline"] = 0xf1358, + ["md-protocol"] = 0xf0fd8, + ["md-publish"] = 0xf06a7, + ["md-publish_off"] = 0xf1945, + ["md-pulse"] = 0xf0430, + ["md-pump"] = 0xf1402, + ["md-pumpkin"] = 0xf0bbf, + ["md-purse"] = 0xf0f1c, + ["md-purse_outline"] = 0xf0f1d, + ["md-puzzle"] = 0xf0431, + ["md-puzzle_check"] = 0xf1426, + ["md-puzzle_check_outline"] = 0xf1427, + ["md-puzzle_edit"] = 0xf14d3, + ["md-puzzle_edit_outline"] = 0xf14d9, + ["md-puzzle_heart"] = 0xf14d4, + ["md-puzzle_heart_outline"] = 0xf14da, + ["md-puzzle_minus"] = 0xf14d1, + ["md-puzzle_minus_outline"] = 0xf14d7, + ["md-puzzle_outline"] = 0xf0a66, + ["md-puzzle_plus"] = 0xf14d0, + ["md-puzzle_plus_outline"] = 0xf14d6, + ["md-puzzle_remove"] = 0xf14d2, + ["md-puzzle_remove_outline"] = 0xf14d8, + ["md-puzzle_star"] = 0xf14d5, + ["md-puzzle_star_outline"] = 0xf14db, + ["md-pyramid"] = 0xf1952, + ["md-pyramid_off"] = 0xf1953, + ["md-qi"] = 0xf0999, + ["md-qqchat"] = 0xf0605, + ["md-qrcode"] = 0xf0432, + ["md-qrcode_edit"] = 0xf08b8, + ["md-qrcode_minus"] = 0xf118c, + ["md-qrcode_plus"] = 0xf118b, + ["md-qrcode_remove"] = 0xf118d, + ["md-qrcode_scan"] = 0xf0433, + ["md-quadcopter"] = 0xf0434, + ["md-quality_high"] = 0xf0435, + ["md-quality_low"] = 0xf0a0c, + ["md-quality_medium"] = 0xf0a0d, + ["md-quora"] = 0xf0d29, + ["md-rabbit"] = 0xf0907, + ["md-rabbit_variant"] = 0xf1a61, + ["md-rabbit_variant_outline"] = 0xf1a62, + ["md-racing_helmet"] = 0xf0d93, + ["md-racquetball"] = 0xf0d94, + ["md-radar"] = 0xf0437, + ["md-radiator"] = 0xf0438, + ["md-radiator_disabled"] = 0xf0ad7, + ["md-radiator_off"] = 0xf0ad8, + ["md-radio"] = 0xf0439, + ["md-radio_am"] = 0xf0cbe, + ["md-radio_fm"] = 0xf0cbf, + ["md-radio_handheld"] = 0xf043a, + ["md-radio_off"] = 0xf121c, + ["md-radio_tower"] = 0xf043b, + ["md-radioactive"] = 0xf043c, + ["md-radioactive_circle"] = 0xf185d, + ["md-radioactive_circle_outline"] = 0xf185e, + ["md-radioactive_off"] = 0xf0ec1, + ["md-radiobox_marked"] = 0xf043e, + ["md-radiology_box"] = 0xf14c5, + ["md-radiology_box_outline"] = 0xf14c6, + ["md-radius"] = 0xf0cc0, + ["md-radius_outline"] = 0xf0cc1, + ["md-railroad_light"] = 0xf0f1e, + ["md-rake"] = 0xf1544, + ["md-raspberry_pi"] = 0xf043f, + ["md-raw"] = 0xf1a0f, + ["md-raw_off"] = 0xf1a10, + ["md-ray_end"] = 0xf0440, + ["md-ray_end_arrow"] = 0xf0441, + ["md-ray_start"] = 0xf0442, + ["md-ray_start_arrow"] = 0xf0443, + ["md-ray_start_end"] = 0xf0444, + ["md-ray_start_vertex_end"] = 0xf15d8, + ["md-ray_vertex"] = 0xf0445, + ["md-razor_double_edge"] = 0xf1997, + ["md-razor_single_edge"] = 0xf1998, + ["md-react"] = 0xf0708, + ["md-read"] = 0xf0447, + ["md-receipt"] = 0xf0449, + ["md-receipt_outline"] = 0xf19dc, + ["md-receipt_text_check"] = 0xf1a63, + ["md-receipt_text_check_outline"] = 0xf1a64, + ["md-receipt_text_minus"] = 0xf1a65, + ["md-receipt_text_minus_outline"] = 0xf1a66, + ["md-receipt_text_plus"] = 0xf1a67, + ["md-receipt_text_plus_outline"] = 0xf1a68, + ["md-receipt_text_remove"] = 0xf1a69, + ["md-receipt_text_remove_outline"] = 0xf1a6a, + ["md-record"] = 0xf044a, + ["md-record_circle"] = 0xf0ec2, + ["md-record_circle_outline"] = 0xf0ec3, + ["md-record_player"] = 0xf099a, + ["md-record_rec"] = 0xf044b, + ["md-rectangle"] = 0xf0e5e, + ["md-rectangle_outline"] = 0xf0e5f, + ["md-recycle"] = 0xf044c, + ["md-recycle_variant"] = 0xf139d, + ["md-reddit"] = 0xf044d, + ["md-redhat"] = 0xf111b, + ["md-redo"] = 0xf044e, + ["md-redo_variant"] = 0xf044f, + ["md-reflect_horizontal"] = 0xf0a0e, + ["md-reflect_vertical"] = 0xf0a0f, + ["md-refresh"] = 0xf0450, + ["md-refresh_auto"] = 0xf18f2, + ["md-refresh_circle"] = 0xf1377, + ["md-regex"] = 0xf0451, + ["md-registered_trademark"] = 0xf0a67, + ["md-reiterate"] = 0xf1588, + ["md-relation_many_to_many"] = 0xf1496, + ["md-relation_many_to_one"] = 0xf1497, + ["md-relation_many_to_one_or_many"] = 0xf1498, + ["md-relation_many_to_only_one"] = 0xf1499, + ["md-relation_many_to_zero_or_many"] = 0xf149a, + ["md-relation_many_to_zero_or_one"] = 0xf149b, + ["md-relation_one_or_many_to_many"] = 0xf149c, + ["md-relation_one_or_many_to_one"] = 0xf149d, + ["md-relation_one_or_many_to_one_or_many"] = 0xf149e, + ["md-relation_one_or_many_to_only_one"] = 0xf149f, + ["md-relation_one_or_many_to_zero_or_many"] = 0xf14a0, + ["md-relation_one_or_many_to_zero_or_one"] = 0xf14a1, + ["md-relation_one_to_many"] = 0xf14a2, + ["md-relation_one_to_one"] = 0xf14a3, + ["md-relation_one_to_one_or_many"] = 0xf14a4, + ["md-relation_one_to_only_one"] = 0xf14a5, + ["md-relation_one_to_zero_or_many"] = 0xf14a6, + ["md-relation_one_to_zero_or_one"] = 0xf14a7, + ["md-relation_only_one_to_many"] = 0xf14a8, + ["md-relation_only_one_to_one"] = 0xf14a9, + ["md-relation_only_one_to_one_or_many"] = 0xf14aa, + ["md-relation_only_one_to_only_one"] = 0xf14ab, + ["md-relation_only_one_to_zero_or_many"] = 0xf14ac, + ["md-relation_only_one_to_zero_or_one"] = 0xf14ad, + ["md-relation_zero_or_many_to_many"] = 0xf14ae, + ["md-relation_zero_or_many_to_one"] = 0xf14af, + ["md-relation_zero_or_many_to_one_or_many"] = 0xf14b0, + ["md-relation_zero_or_many_to_only_one"] = 0xf14b1, + ["md-relation_zero_or_many_to_zero_or_many"] = 0xf14b2, + ["md-relation_zero_or_many_to_zero_or_one"] = 0xf14b3, + ["md-relation_zero_or_one_to_many"] = 0xf14b4, + ["md-relation_zero_or_one_to_one"] = 0xf14b5, + ["md-relation_zero_or_one_to_one_or_many"] = 0xf14b6, + ["md-relation_zero_or_one_to_only_one"] = 0xf14b7, + ["md-relation_zero_or_one_to_zero_or_many"] = 0xf14b8, + ["md-relation_zero_or_one_to_zero_or_one"] = 0xf14b9, + ["md-relative_scale"] = 0xf0452, + ["md-reload"] = 0xf0453, + ["md-reload_alert"] = 0xf110b, + ["md-reminder"] = 0xf088c, + ["md-remote"] = 0xf0454, + ["md-remote_desktop"] = 0xf08b9, + ["md-remote_off"] = 0xf0ec4, + ["md-remote_tv"] = 0xf0ec5, + ["md-remote_tv_off"] = 0xf0ec6, + ["md-rename_box"] = 0xf0455, + ["md-reorder_horizontal"] = 0xf0688, + ["md-reorder_vertical"] = 0xf0689, + ["md-repeat"] = 0xf0456, + ["md-repeat_off"] = 0xf0457, + ["md-repeat_once"] = 0xf0458, + ["md-repeat_variant"] = 0xf0547, + ["md-replay"] = 0xf0459, + ["md-reply"] = 0xf045a, + ["md-reply_all"] = 0xf045b, + ["md-reply_all_outline"] = 0xf0f1f, + ["md-reply_circle"] = 0xf11ae, + ["md-reply_outline"] = 0xf0f20, + ["md-reproduction"] = 0xf045c, + ["md-resistor"] = 0xf0b44, + ["md-resistor_nodes"] = 0xf0b45, + ["md-resize"] = 0xf0a68, + ["md-resize_bottom_right"] = 0xf045d, + ["md-responsive"] = 0xf045e, + ["md-restart"] = 0xf0709, + ["md-restart_alert"] = 0xf110c, + ["md-restart_off"] = 0xf0d95, + ["md-restore"] = 0xf099b, + ["md-restore_alert"] = 0xf110d, + ["md-rewind"] = 0xf045f, + ["md-rewind_10"] = 0xf0d2a, + ["md-rewind_15"] = 0xf1946, + ["md-rewind_30"] = 0xf0d96, + ["md-rewind_5"] = 0xf11f9, + ["md-rewind_60"] = 0xf160c, + ["md-rewind_outline"] = 0xf070a, + ["md-rhombus"] = 0xf070b, + ["md-rhombus_medium"] = 0xf0a10, + ["md-rhombus_medium_outline"] = 0xf14dc, + ["md-rhombus_outline"] = 0xf070c, + ["md-rhombus_split"] = 0xf0a11, + ["md-rhombus_split_outline"] = 0xf14dd, + ["md-ribbon"] = 0xf0460, + ["md-rice"] = 0xf07ea, + ["md-rickshaw"] = 0xf15bb, + ["md-rickshaw_electric"] = 0xf15bc, + ["md-ring"] = 0xf07eb, + ["md-rivet"] = 0xf0e60, + ["md-road"] = 0xf0461, + ["md-road_variant"] = 0xf0462, + ["md-robber"] = 0xf1058, + ["md-robot"] = 0xf06a9, + ["md-robot_angry"] = 0xf169d, + ["md-robot_angry_outline"] = 0xf169e, + ["md-robot_confused"] = 0xf169f, + ["md-robot_confused_outline"] = 0xf16a0, + ["md-robot_dead"] = 0xf16a1, + ["md-robot_dead_outline"] = 0xf16a2, + ["md-robot_excited"] = 0xf16a3, + ["md-robot_excited_outline"] = 0xf16a4, + ["md-robot_happy"] = 0xf1719, + ["md-robot_happy_outline"] = 0xf171a, + ["md-robot_industrial"] = 0xf0b46, + ["md-robot_industrial_outline"] = 0xf1a1a, + ["md-robot_love"] = 0xf16a5, + ["md-robot_love_outline"] = 0xf16a6, + ["md-robot_mower"] = 0xf11f7, + ["md-robot_mower_outline"] = 0xf11f3, + ["md-robot_off"] = 0xf16a7, + ["md-robot_off_outline"] = 0xf167b, + ["md-robot_outline"] = 0xf167a, + ["md-robot_vacuum"] = 0xf070d, + ["md-robot_vacuum_variant"] = 0xf0908, + ["md-rocket"] = 0xf0463, + ["md-rocket_launch"] = 0xf14de, + ["md-rocket_launch_outline"] = 0xf14df, + ["md-rocket_outline"] = 0xf13af, + ["md-rodent"] = 0xf1327, + ["md-roller_shade"] = 0xf1a6b, + ["md-roller_shade_closed"] = 0xf1a6c, + ["md-roller_skate"] = 0xf0d2b, + ["md-roller_skate_off"] = 0xf0145, + ["md-rollerblade"] = 0xf0d2c, + ["md-rollerblade_off"] = 0xf002e, + ["md-rollupjs"] = 0xf0bc0, + ["md-rolodex"] = 0xf1ab9, + ["md-rolodex_outline"] = 0xf1aba, + ["md-roman_numeral_2"] = 0xf1089, + ["md-roman_numeral_3"] = 0xf108a, + ["md-roman_numeral_4"] = 0xf108b, + ["md-roman_numeral_6"] = 0xf108d, + ["md-roman_numeral_7"] = 0xf108e, + ["md-roman_numeral_8"] = 0xf108f, + ["md-roman_numeral_9"] = 0xf1090, + ["md-room_service"] = 0xf088d, + ["md-room_service_outline"] = 0xf0d97, + ["md-rotate_360"] = 0xf1999, + ["md-rotate_3d"] = 0xf0ec7, + ["md-rotate_3d_variant"] = 0xf0464, + ["md-rotate_left"] = 0xf0465, + ["md-rotate_left_variant"] = 0xf0466, + ["md-rotate_orbit"] = 0xf0d98, + ["md-rotate_right"] = 0xf0467, + ["md-rotate_right_variant"] = 0xf0468, + ["md-rounded_corner"] = 0xf0607, + ["md-router"] = 0xf11e2, + ["md-router_network"] = 0xf1087, + ["md-router_wireless"] = 0xf0469, + ["md-router_wireless_off"] = 0xf15a3, + ["md-router_wireless_settings"] = 0xf0a69, + ["md-routes"] = 0xf046a, + ["md-routes_clock"] = 0xf1059, + ["md-rowing"] = 0xf0608, + ["md-rss"] = 0xf046b, + ["md-rss_box"] = 0xf046c, + ["md-rss_off"] = 0xf0f21, + ["md-rug"] = 0xf1475, + ["md-rugby"] = 0xf0d99, + ["md-ruler"] = 0xf046d, + ["md-ruler_square"] = 0xf0cc2, + ["md-ruler_square_compass"] = 0xf0ebe, + ["md-run"] = 0xf070e, + ["md-run_fast"] = 0xf046e, + ["md-rv_truck"] = 0xf11d4, + ["md-sack"] = 0xf0d2e, + ["md-sack_percent"] = 0xf0d2f, + ["md-safe"] = 0xf0a6a, + ["md-safe_square"] = 0xf127c, + ["md-safe_square_outline"] = 0xf127d, + ["md-safety_goggles"] = 0xf0d30, + ["md-sail_boat"] = 0xf0ec8, + ["md-sail_boat_sink"] = 0xf1aef, + ["md-sale"] = 0xf046f, + ["md-sale_outline"] = 0xf1a06, + ["md-salesforce"] = 0xf088e, + ["md-sass"] = 0xf07ec, + ["md-satellite"] = 0xf0470, + ["md-satellite_uplink"] = 0xf0909, + ["md-satellite_variant"] = 0xf0471, + ["md-sausage"] = 0xf08ba, + ["md-sausage_off"] = 0xf1789, + ["md-saw_blade"] = 0xf0e61, + ["md-sawtooth_wave"] = 0xf147a, + ["md-saxophone"] = 0xf0609, + ["md-scale"] = 0xf0472, + ["md-scale_balance"] = 0xf05d1, + ["md-scale_bathroom"] = 0xf0473, + ["md-scale_off"] = 0xf105a, + ["md-scale_unbalanced"] = 0xf19b8, + ["md-scan_helper"] = 0xf13d8, + ["md-scanner"] = 0xf06ab, + ["md-scanner_off"] = 0xf090a, + ["md-scatter_plot"] = 0xf0ec9, + ["md-scatter_plot_outline"] = 0xf0eca, + ["md-scent"] = 0xf1958, + ["md-scent_off"] = 0xf1959, + ["md-school"] = 0xf0474, + ["md-school_outline"] = 0xf1180, + ["md-scissors_cutting"] = 0xf0a6b, + ["md-scooter"] = 0xf15bd, + ["md-scooter_electric"] = 0xf15be, + ["md-scoreboard"] = 0xf127e, + ["md-scoreboard_outline"] = 0xf127f, + ["md-screen_rotation"] = 0xf0475, + ["md-screen_rotation_lock"] = 0xf0478, + ["md-screw_flat_top"] = 0xf0df3, + ["md-screw_lag"] = 0xf0df4, + ["md-screw_machine_flat_top"] = 0xf0df5, + ["md-screw_machine_round_top"] = 0xf0df6, + ["md-screw_round_top"] = 0xf0df7, + ["md-screwdriver"] = 0xf0476, + ["md-script"] = 0xf0bc1, + ["md-script_outline"] = 0xf0477, + ["md-script_text"] = 0xf0bc2, + ["md-script_text_key"] = 0xf1725, + ["md-script_text_key_outline"] = 0xf1726, + ["md-script_text_outline"] = 0xf0bc3, + ["md-script_text_play"] = 0xf1727, + ["md-script_text_play_outline"] = 0xf1728, + ["md-sd"] = 0xf0479, + ["md-seal"] = 0xf047a, + ["md-seal_variant"] = 0xf0fd9, + ["md-search_web"] = 0xf070f, + ["md-seat"] = 0xf0cc3, + ["md-seat_flat"] = 0xf047b, + ["md-seat_flat_angled"] = 0xf047c, + ["md-seat_individual_suite"] = 0xf047d, + ["md-seat_legroom_extra"] = 0xf047e, + ["md-seat_legroom_normal"] = 0xf047f, + ["md-seat_legroom_reduced"] = 0xf0480, + ["md-seat_outline"] = 0xf0cc4, + ["md-seat_passenger"] = 0xf1249, + ["md-seat_recline_extra"] = 0xf0481, + ["md-seat_recline_normal"] = 0xf0482, + ["md-seatbelt"] = 0xf0cc5, + ["md-security"] = 0xf0483, + ["md-security_network"] = 0xf0484, + ["md-seed"] = 0xf0e62, + ["md-seed_off"] = 0xf13fd, + ["md-seed_off_outline"] = 0xf13fe, + ["md-seed_outline"] = 0xf0e63, + ["md-seed_plus"] = 0xf1a6d, + ["md-seed_plus_outline"] = 0xf1a6e, + ["md-seesaw"] = 0xf15a4, + ["md-segment"] = 0xf0ecb, + ["md-select"] = 0xf0485, + ["md-select_all"] = 0xf0486, + ["md-select_color"] = 0xf0d31, + ["md-select_compare"] = 0xf0ad9, + ["md-select_drag"] = 0xf0a6c, + ["md-select_group"] = 0xf0f82, + ["md-select_inverse"] = 0xf0487, + ["md-select_marker"] = 0xf1280, + ["md-select_multiple"] = 0xf1281, + ["md-select_multiple_marker"] = 0xf1282, + ["md-select_off"] = 0xf0488, + ["md-select_place"] = 0xf0fda, + ["md-select_remove"] = 0xf17c1, + ["md-select_search"] = 0xf1204, + ["md-selection"] = 0xf0489, + ["md-selection_drag"] = 0xf0a6d, + ["md-selection_ellipse"] = 0xf0d32, + ["md-selection_ellipse_arrow_inside"] = 0xf0f22, + ["md-selection_ellipse_remove"] = 0xf17c2, + ["md-selection_marker"] = 0xf1283, + ["md-selection_multiple"] = 0xf1285, + ["md-selection_multiple_marker"] = 0xf1284, + ["md-selection_off"] = 0xf0777, + ["md-selection_remove"] = 0xf17c3, + ["md-selection_search"] = 0xf1205, + ["md-semantic_web"] = 0xf1316, + ["md-send"] = 0xf048a, + ["md-send_check"] = 0xf1161, + ["md-send_check_outline"] = 0xf1162, + ["md-send_circle"] = 0xf0df8, + ["md-send_circle_outline"] = 0xf0df9, + ["md-send_clock"] = 0xf1163, + ["md-send_clock_outline"] = 0xf1164, + ["md-send_lock"] = 0xf07ed, + ["md-send_lock_outline"] = 0xf1166, + ["md-send_outline"] = 0xf1165, + ["md-serial_port"] = 0xf065c, + ["md-server"] = 0xf048b, + ["md-server_minus"] = 0xf048c, + ["md-server_network"] = 0xf048d, + ["md-server_network_off"] = 0xf048e, + ["md-server_off"] = 0xf048f, + ["md-server_plus"] = 0xf0490, + ["md-server_remove"] = 0xf0491, + ["md-server_security"] = 0xf0492, + ["md-set_all"] = 0xf0778, + ["md-set_center"] = 0xf0779, + ["md-set_center_right"] = 0xf077a, + ["md-set_left"] = 0xf077b, + ["md-set_left_center"] = 0xf077c, + ["md-set_left_right"] = 0xf077d, + ["md-set_merge"] = 0xf14e0, + ["md-set_none"] = 0xf077e, + ["md-set_right"] = 0xf077f, + ["md-set_split"] = 0xf14e1, + ["md-set_square"] = 0xf145d, + ["md-set_top_box"] = 0xf099f, + ["md-settings_helper"] = 0xf0a6e, + ["md-shaker"] = 0xf110e, + ["md-shaker_outline"] = 0xf110f, + ["md-shape"] = 0xf0831, + ["md-shape_circle_plus"] = 0xf065d, + ["md-shape_outline"] = 0xf0832, + ["md-shape_oval_plus"] = 0xf11fa, + ["md-shape_plus"] = 0xf0495, + ["md-shape_polygon_plus"] = 0xf065e, + ["md-shape_rectangle_plus"] = 0xf065f, + ["md-shape_square_plus"] = 0xf0660, + ["md-shape_square_rounded_plus"] = 0xf14fa, + ["md-share"] = 0xf0496, + ["md-share_all"] = 0xf11f4, + ["md-share_all_outline"] = 0xf11f5, + ["md-share_circle"] = 0xf11ad, + ["md-share_off"] = 0xf0f23, + ["md-share_off_outline"] = 0xf0f24, + ["md-share_outline"] = 0xf0932, + ["md-share_variant"] = 0xf0497, + ["md-share_variant_outline"] = 0xf1514, + ["md-shark"] = 0xf18ba, + ["md-shark_fin"] = 0xf1673, + ["md-shark_fin_outline"] = 0xf1674, + ["md-shark_off"] = 0xf18bb, + ["md-sheep"] = 0xf0cc6, + ["md-shield"] = 0xf0498, + ["md-shield_account"] = 0xf088f, + ["md-shield_account_outline"] = 0xf0a12, + ["md-shield_account_variant"] = 0xf15a7, + ["md-shield_account_variant_outline"] = 0xf15a8, + ["md-shield_airplane"] = 0xf06bb, + ["md-shield_airplane_outline"] = 0xf0cc7, + ["md-shield_alert"] = 0xf0ecc, + ["md-shield_alert_outline"] = 0xf0ecd, + ["md-shield_bug"] = 0xf13da, + ["md-shield_bug_outline"] = 0xf13db, + ["md-shield_car"] = 0xf0f83, + ["md-shield_check"] = 0xf0565, + ["md-shield_check_outline"] = 0xf0cc8, + ["md-shield_cross"] = 0xf0cc9, + ["md-shield_cross_outline"] = 0xf0cca, + ["md-shield_crown"] = 0xf18bc, + ["md-shield_crown_outline"] = 0xf18bd, + ["md-shield_edit"] = 0xf11a0, + ["md-shield_edit_outline"] = 0xf11a1, + ["md-shield_half"] = 0xf1360, + ["md-shield_half_full"] = 0xf0780, + ["md-shield_home"] = 0xf068a, + ["md-shield_home_outline"] = 0xf0ccb, + ["md-shield_key"] = 0xf0bc4, + ["md-shield_key_outline"] = 0xf0bc5, + ["md-shield_link_variant"] = 0xf0d33, + ["md-shield_link_variant_outline"] = 0xf0d34, + ["md-shield_lock"] = 0xf099d, + ["md-shield_lock_open"] = 0xf199a, + ["md-shield_lock_open_outline"] = 0xf199b, + ["md-shield_lock_outline"] = 0xf0ccc, + ["md-shield_moon"] = 0xf1828, + ["md-shield_moon_outline"] = 0xf1829, + ["md-shield_off"] = 0xf099e, + ["md-shield_off_outline"] = 0xf099c, + ["md-shield_outline"] = 0xf0499, + ["md-shield_plus"] = 0xf0ada, + ["md-shield_plus_outline"] = 0xf0adb, + ["md-shield_refresh"] = 0xf00aa, + ["md-shield_refresh_outline"] = 0xf01e0, + ["md-shield_remove"] = 0xf0adc, + ["md-shield_remove_outline"] = 0xf0add, + ["md-shield_search"] = 0xf0d9a, + ["md-shield_star"] = 0xf113b, + ["md-shield_star_outline"] = 0xf113c, + ["md-shield_sun"] = 0xf105d, + ["md-shield_sun_outline"] = 0xf105e, + ["md-shield_sword"] = 0xf18be, + ["md-shield_sword_outline"] = 0xf18bf, + ["md-shield_sync"] = 0xf11a2, + ["md-shield_sync_outline"] = 0xf11a3, + ["md-shimmer"] = 0xf1545, + ["md-ship_wheel"] = 0xf0833, + ["md-shipping_pallet"] = 0xf184e, + ["md-shoe_ballet"] = 0xf15ca, + ["md-shoe_cleat"] = 0xf15c7, + ["md-shoe_formal"] = 0xf0b47, + ["md-shoe_heel"] = 0xf0b48, + ["md-shoe_print"] = 0xf0dfa, + ["md-shoe_sneaker"] = 0xf15c8, + ["md-shopping"] = 0xf049a, + ["md-shopping_music"] = 0xf049b, + ["md-shopping_outline"] = 0xf11d5, + ["md-shopping_search"] = 0xf0f84, + ["md-shopping_search_outline"] = 0xf1a6f, + ["md-shore"] = 0xf14f9, + ["md-shovel"] = 0xf0710, + ["md-shovel_off"] = 0xf0711, + ["md-shower"] = 0xf09a0, + ["md-shower_head"] = 0xf09a1, + ["md-shredder"] = 0xf049c, + ["md-shuffle"] = 0xf049d, + ["md-shuffle_disabled"] = 0xf049e, + ["md-shuffle_variant"] = 0xf049f, + ["md-shuriken"] = 0xf137f, + ["md-sickle"] = 0xf18c0, + ["md-sigma"] = 0xf04a0, + ["md-sigma_lower"] = 0xf062b, + ["md-sign_caution"] = 0xf04a1, + ["md-sign_direction"] = 0xf0781, + ["md-sign_direction_minus"] = 0xf1000, + ["md-sign_direction_plus"] = 0xf0fdc, + ["md-sign_direction_remove"] = 0xf0fdd, + ["md-sign_pole"] = 0xf14f8, + ["md-sign_real_estate"] = 0xf1118, + ["md-sign_text"] = 0xf0782, + ["md-signal"] = 0xf04a2, + ["md-signal_2g"] = 0xf0712, + ["md-signal_3g"] = 0xf0713, + ["md-signal_4g"] = 0xf0714, + ["md-signal_5g"] = 0xf0a6f, + ["md-signal_cellular_1"] = 0xf08bc, + ["md-signal_cellular_2"] = 0xf08bd, + ["md-signal_cellular_3"] = 0xf08be, + ["md-signal_cellular_outline"] = 0xf08bf, + ["md-signal_distance_variant"] = 0xf0e64, + ["md-signal_hspa"] = 0xf0715, + ["md-signal_hspa_plus"] = 0xf0716, + ["md-signal_off"] = 0xf0783, + ["md-signal_variant"] = 0xf060a, + ["md-signature"] = 0xf0dfb, + ["md-signature_freehand"] = 0xf0dfc, + ["md-signature_image"] = 0xf0dfd, + ["md-signature_text"] = 0xf0dfe, + ["md-silo"] = 0xf0b49, + ["md-silverware"] = 0xf04a3, + ["md-silverware_clean"] = 0xf0fde, + ["md-silverware_fork"] = 0xf04a4, + ["md-silverware_fork_knife"] = 0xf0a70, + ["md-silverware_spoon"] = 0xf04a5, + ["md-silverware_variant"] = 0xf04a6, + ["md-sim"] = 0xf04a7, + ["md-sim_alert"] = 0xf04a8, + ["md-sim_alert_outline"] = 0xf15d3, + ["md-sim_off"] = 0xf04a9, + ["md-sim_off_outline"] = 0xf15d4, + ["md-sim_outline"] = 0xf15d5, + ["md-simple_icons"] = 0xf131d, + ["md-sina_weibo"] = 0xf0adf, + ["md-sine_wave"] = 0xf095b, + ["md-sitemap"] = 0xf04aa, + ["md-sitemap_outline"] = 0xf199c, + ["md-size_m"] = 0xf13a5, + ["md-size_s"] = 0xf13a4, + ["md-size_xl"] = 0xf13a7, + ["md-size_xs"] = 0xf13a3, + ["md-size_xxl"] = 0xf13a8, + ["md-size_xxs"] = 0xf13a2, + ["md-size_xxxl"] = 0xf13a9, + ["md-skate"] = 0xf0d35, + ["md-skate_off"] = 0xf0699, + ["md-skateboard"] = 0xf14c2, + ["md-skateboarding"] = 0xf0501, + ["md-skew_less"] = 0xf0d36, + ["md-skew_more"] = 0xf0d37, + ["md-ski"] = 0xf1304, + ["md-ski_cross_country"] = 0xf1305, + ["md-ski_water"] = 0xf1306, + ["md-skip_backward"] = 0xf04ab, + ["md-skip_backward_outline"] = 0xf0f25, + ["md-skip_forward"] = 0xf04ac, + ["md-skip_forward_outline"] = 0xf0f26, + ["md-skip_next"] = 0xf04ad, + ["md-skip_next_circle"] = 0xf0661, + ["md-skip_next_circle_outline"] = 0xf0662, + ["md-skip_next_outline"] = 0xf0f27, + ["md-skip_previous"] = 0xf04ae, + ["md-skip_previous_circle"] = 0xf0663, + ["md-skip_previous_circle_outline"] = 0xf0664, + ["md-skip_previous_outline"] = 0xf0f28, + ["md-skull"] = 0xf068c, + ["md-skull_crossbones"] = 0xf0bc6, + ["md-skull_crossbones_outline"] = 0xf0bc7, + ["md-skull_outline"] = 0xf0bc8, + ["md-skull_scan"] = 0xf14c7, + ["md-skull_scan_outline"] = 0xf14c8, + ["md-skype"] = 0xf04af, + ["md-skype_business"] = 0xf04b0, + ["md-slack"] = 0xf04b1, + ["md-slash_forward"] = 0xf0fdf, + ["md-slash_forward_box"] = 0xf0fe0, + ["md-sledding"] = 0xf041b, + ["md-sleep"] = 0xf04b2, + ["md-sleep_off"] = 0xf04b3, + ["md-slide"] = 0xf15a5, + ["md-slope_downhill"] = 0xf0dff, + ["md-slope_uphill"] = 0xf0e00, + ["md-slot_machine"] = 0xf1114, + ["md-slot_machine_outline"] = 0xf1115, + ["md-smart_card"] = 0xf10bd, + ["md-smart_card_off"] = 0xf18f7, + ["md-smart_card_off_outline"] = 0xf18f8, + ["md-smart_card_outline"] = 0xf10be, + ["md-smart_card_reader"] = 0xf10bf, + ["md-smart_card_reader_outline"] = 0xf10c0, + ["md-smog"] = 0xf0a71, + ["md-smoke"] = 0xf1799, + ["md-smoke_detector"] = 0xf0392, + ["md-smoke_detector_alert"] = 0xf192e, + ["md-smoke_detector_alert_outline"] = 0xf192f, + ["md-smoke_detector_off"] = 0xf1809, + ["md-smoke_detector_off_outline"] = 0xf180a, + ["md-smoke_detector_outline"] = 0xf1808, + ["md-smoke_detector_variant"] = 0xf180b, + ["md-smoke_detector_variant_alert"] = 0xf1930, + ["md-smoke_detector_variant_off"] = 0xf180c, + ["md-smoking"] = 0xf04b4, + ["md-smoking_off"] = 0xf04b5, + ["md-smoking_pipe"] = 0xf140d, + ["md-smoking_pipe_off"] = 0xf1428, + ["md-snail"] = 0xf1677, + ["md-snake"] = 0xf150e, + ["md-snapchat"] = 0xf04b6, + ["md-snowboard"] = 0xf1307, + ["md-snowflake"] = 0xf0717, + ["md-snowflake_alert"] = 0xf0f29, + ["md-snowflake_check"] = 0xf1a70, + ["md-snowflake_melt"] = 0xf12cb, + ["md-snowflake_off"] = 0xf14e3, + ["md-snowflake_thermometer"] = 0xf1a71, + ["md-snowflake_variant"] = 0xf0f2a, + ["md-snowman"] = 0xf04b7, + ["md-snowmobile"] = 0xf06dd, + ["md-snowshoeing"] = 0xf1a72, + ["md-soccer"] = 0xf04b8, + ["md-soccer_field"] = 0xf0834, + ["md-social_distance_2_meters"] = 0xf1579, + ["md-social_distance_6_feet"] = 0xf157a, + ["md-sofa"] = 0xf04b9, + ["md-sofa_outline"] = 0xf156d, + ["md-sofa_single"] = 0xf156e, + ["md-sofa_single_outline"] = 0xf156f, + ["md-solar_panel"] = 0xf0d9b, + ["md-solar_panel_large"] = 0xf0d9c, + ["md-solar_power"] = 0xf0a72, + ["md-solar_power_variant"] = 0xf1a73, + ["md-solar_power_variant_outline"] = 0xf1a74, + ["md-soldering_iron"] = 0xf1092, + ["md-solid"] = 0xf068d, + ["md-sony_playstation"] = 0xf0414, + ["md-sort"] = 0xf04ba, + ["md-sort_alphabetical_ascending"] = 0xf05bd, + ["md-sort_alphabetical_ascending_variant"] = 0xf1148, + ["md-sort_alphabetical_descending"] = 0xf05bf, + ["md-sort_alphabetical_descending_variant"] = 0xf1149, + ["md-sort_alphabetical_variant"] = 0xf04bb, + ["md-sort_ascending"] = 0xf04bc, + ["md-sort_bool_ascending"] = 0xf1385, + ["md-sort_bool_ascending_variant"] = 0xf1386, + ["md-sort_bool_descending"] = 0xf1387, + ["md-sort_bool_descending_variant"] = 0xf1388, + ["md-sort_calendar_ascending"] = 0xf1547, + ["md-sort_calendar_descending"] = 0xf1548, + ["md-sort_clock_ascending"] = 0xf1549, + ["md-sort_clock_ascending_outline"] = 0xf154a, + ["md-sort_clock_descending"] = 0xf154b, + ["md-sort_clock_descending_outline"] = 0xf154c, + ["md-sort_descending"] = 0xf04bd, + ["md-sort_numeric_ascending"] = 0xf1389, + ["md-sort_numeric_ascending_variant"] = 0xf090d, + ["md-sort_numeric_descending"] = 0xf138a, + ["md-sort_numeric_descending_variant"] = 0xf0ad2, + ["md-sort_numeric_variant"] = 0xf04be, + ["md-sort_reverse_variant"] = 0xf033c, + ["md-sort_variant"] = 0xf04bf, + ["md-sort_variant_lock"] = 0xf0ccd, + ["md-sort_variant_lock_open"] = 0xf0cce, + ["md-sort_variant_off"] = 0xf1abb, + ["md-sort_variant_remove"] = 0xf1147, + ["md-soundbar"] = 0xf17db, + ["md-soundcloud"] = 0xf04c0, + ["md-source_branch"] = 0xf062c, + ["md-source_branch_check"] = 0xf14cf, + ["md-source_branch_minus"] = 0xf14cb, + ["md-source_branch_plus"] = 0xf14ca, + ["md-source_branch_refresh"] = 0xf14cd, + ["md-source_branch_remove"] = 0xf14cc, + ["md-source_branch_sync"] = 0xf14ce, + ["md-source_commit"] = 0xf0718, + ["md-source_commit_end"] = 0xf0719, + ["md-source_commit_end_local"] = 0xf071a, + ["md-source_commit_local"] = 0xf071b, + ["md-source_commit_next_local"] = 0xf071c, + ["md-source_commit_start"] = 0xf071d, + ["md-source_commit_start_next_local"] = 0xf071e, + ["md-source_fork"] = 0xf04c1, + ["md-source_merge"] = 0xf062d, + ["md-source_pull"] = 0xf04c2, + ["md-source_repository"] = 0xf0ccf, + ["md-source_repository_multiple"] = 0xf0cd0, + ["md-soy_sauce"] = 0xf07ee, + ["md-soy_sauce_off"] = 0xf13fc, + ["md-spa"] = 0xf0cd1, + ["md-spa_outline"] = 0xf0cd2, + ["md-space_invaders"] = 0xf0bc9, + ["md-space_station"] = 0xf1383, + ["md-spade"] = 0xf0e65, + ["md-speaker"] = 0xf04c3, + ["md-speaker_bluetooth"] = 0xf09a2, + ["md-speaker_multiple"] = 0xf0d38, + ["md-speaker_off"] = 0xf04c4, + ["md-speaker_wireless"] = 0xf071f, + ["md-spear"] = 0xf1845, + ["md-speedometer"] = 0xf04c5, + ["md-speedometer_medium"] = 0xf0f85, + ["md-speedometer_slow"] = 0xf0f86, + ["md-spellcheck"] = 0xf04c6, + ["md-sphere"] = 0xf1954, + ["md-sphere_off"] = 0xf1955, + ["md-spider"] = 0xf11ea, + ["md-spider_thread"] = 0xf11eb, + ["md-spider_web"] = 0xf0bca, + ["md-spirit_level"] = 0xf14f1, + ["md-spoon_sugar"] = 0xf1429, + ["md-spotify"] = 0xf04c7, + ["md-spotlight"] = 0xf04c8, + ["md-spotlight_beam"] = 0xf04c9, + ["md-spray"] = 0xf0665, + ["md-spray_bottle"] = 0xf0ae0, + ["md-sprinkler"] = 0xf105f, + ["md-sprinkler_fire"] = 0xf199d, + ["md-sprinkler_variant"] = 0xf1060, + ["md-sprout"] = 0xf0e66, + ["md-sprout_outline"] = 0xf0e67, + ["md-square"] = 0xf0764, + ["md-square_circle"] = 0xf1500, + ["md-square_edit_outline"] = 0xf090c, + ["md-square_medium"] = 0xf0a13, + ["md-square_medium_outline"] = 0xf0a14, + ["md-square_off"] = 0xf12ee, + ["md-square_off_outline"] = 0xf12ef, + ["md-square_opacity"] = 0xf1854, + ["md-square_outline"] = 0xf0763, + ["md-square_root"] = 0xf0784, + ["md-square_root_box"] = 0xf09a3, + ["md-square_rounded"] = 0xf14fb, + ["md-square_rounded_badge"] = 0xf1a07, + ["md-square_rounded_badge_outline"] = 0xf1a08, + ["md-square_rounded_outline"] = 0xf14fc, + ["md-square_small"] = 0xf0a15, + ["md-square_wave"] = 0xf147b, + ["md-squeegee"] = 0xf0ae1, + ["md-ssh"] = 0xf08c0, + ["md-stack_exchange"] = 0xf060b, + ["md-stack_overflow"] = 0xf04cc, + ["md-stackpath"] = 0xf0359, + ["md-stadium"] = 0xf0ff9, + ["md-stadium_variant"] = 0xf0720, + ["md-stairs"] = 0xf04cd, + ["md-stairs_box"] = 0xf139e, + ["md-stairs_down"] = 0xf12be, + ["md-stairs_up"] = 0xf12bd, + ["md-stamper"] = 0xf0d39, + ["md-standard_definition"] = 0xf07ef, + ["md-star"] = 0xf04ce, + ["md-star_box"] = 0xf0a73, + ["md-star_box_multiple"] = 0xf1286, + ["md-star_box_multiple_outline"] = 0xf1287, + ["md-star_box_outline"] = 0xf0a74, + ["md-star_check"] = 0xf1566, + ["md-star_check_outline"] = 0xf156a, + ["md-star_circle"] = 0xf04cf, + ["md-star_circle_outline"] = 0xf09a4, + ["md-star_cog"] = 0xf1668, + ["md-star_cog_outline"] = 0xf1669, + ["md-star_crescent"] = 0xf0979, + ["md-star_david"] = 0xf097a, + ["md-star_face"] = 0xf09a5, + ["md-star_four_points"] = 0xf0ae2, + ["md-star_four_points_outline"] = 0xf0ae3, + ["md-star_half"] = 0xf0246, + ["md-star_half_full"] = 0xf04d0, + ["md-star_minus"] = 0xf1564, + ["md-star_minus_outline"] = 0xf1568, + ["md-star_off"] = 0xf04d1, + ["md-star_off_outline"] = 0xf155b, + ["md-star_outline"] = 0xf04d2, + ["md-star_plus"] = 0xf1563, + ["md-star_plus_outline"] = 0xf1567, + ["md-star_remove"] = 0xf1565, + ["md-star_remove_outline"] = 0xf1569, + ["md-star_settings"] = 0xf166a, + ["md-star_settings_outline"] = 0xf166b, + ["md-star_shooting"] = 0xf1741, + ["md-star_shooting_outline"] = 0xf1742, + ["md-star_three_points"] = 0xf0ae4, + ["md-star_three_points_outline"] = 0xf0ae5, + ["md-state_machine"] = 0xf11ef, + ["md-steam"] = 0xf04d3, + ["md-steering"] = 0xf04d4, + ["md-steering_off"] = 0xf090e, + ["md-step_backward"] = 0xf04d5, + ["md-step_backward_2"] = 0xf04d6, + ["md-step_forward"] = 0xf04d7, + ["md-step_forward_2"] = 0xf04d8, + ["md-stethoscope"] = 0xf04d9, + ["md-sticker"] = 0xf1364, + ["md-sticker_alert"] = 0xf1365, + ["md-sticker_alert_outline"] = 0xf1366, + ["md-sticker_check"] = 0xf1367, + ["md-sticker_check_outline"] = 0xf1368, + ["md-sticker_circle_outline"] = 0xf05d0, + ["md-sticker_emoji"] = 0xf0785, + ["md-sticker_minus"] = 0xf1369, + ["md-sticker_minus_outline"] = 0xf136a, + ["md-sticker_outline"] = 0xf136b, + ["md-sticker_plus"] = 0xf136c, + ["md-sticker_plus_outline"] = 0xf136d, + ["md-sticker_remove"] = 0xf136e, + ["md-sticker_remove_outline"] = 0xf136f, + ["md-sticker_text"] = 0xf178e, + ["md-sticker_text_outline"] = 0xf178f, + ["md-stocking"] = 0xf04da, + ["md-stomach"] = 0xf1093, + ["md-stool"] = 0xf195d, + ["md-stool_outline"] = 0xf195e, + ["md-stop"] = 0xf04db, + ["md-stop_circle"] = 0xf0666, + ["md-stop_circle_outline"] = 0xf0667, + ["md-storage_tank"] = 0xf1a75, + ["md-storage_tank_outline"] = 0xf1a76, + ["md-store"] = 0xf04dc, + ["md-store_24_hour"] = 0xf04dd, + ["md-store_alert"] = 0xf18c1, + ["md-store_alert_outline"] = 0xf18c2, + ["md-store_check"] = 0xf18c3, + ["md-store_check_outline"] = 0xf18c4, + ["md-store_clock"] = 0xf18c5, + ["md-store_clock_outline"] = 0xf18c6, + ["md-store_cog"] = 0xf18c7, + ["md-store_cog_outline"] = 0xf18c8, + ["md-store_edit"] = 0xf18c9, + ["md-store_edit_outline"] = 0xf18ca, + ["md-store_marker"] = 0xf18cb, + ["md-store_marker_outline"] = 0xf18cc, + ["md-store_minus"] = 0xf165e, + ["md-store_minus_outline"] = 0xf18cd, + ["md-store_off"] = 0xf18ce, + ["md-store_off_outline"] = 0xf18cf, + ["md-store_outline"] = 0xf1361, + ["md-store_plus"] = 0xf165f, + ["md-store_plus_outline"] = 0xf18d0, + ["md-store_remove"] = 0xf1660, + ["md-store_remove_outline"] = 0xf18d1, + ["md-store_search"] = 0xf18d2, + ["md-store_search_outline"] = 0xf18d3, + ["md-store_settings"] = 0xf18d4, + ["md-store_settings_outline"] = 0xf18d5, + ["md-storefront"] = 0xf07c7, + ["md-storefront_outline"] = 0xf10c1, + ["md-stove"] = 0xf04de, + ["md-strategy"] = 0xf11d6, + ["md-stretch_to_page"] = 0xf0f2b, + ["md-stretch_to_page_outline"] = 0xf0f2c, + ["md-string_lights"] = 0xf12ba, + ["md-string_lights_off"] = 0xf12bb, + ["md-subdirectory_arrow_left"] = 0xf060c, + ["md-subdirectory_arrow_right"] = 0xf060d, + ["md-submarine"] = 0xf156c, + ["md-subtitles"] = 0xf0a16, + ["md-subtitles_outline"] = 0xf0a17, + ["md-subway"] = 0xf06ac, + ["md-subway_alert_variant"] = 0xf0d9d, + ["md-subway_variant"] = 0xf04df, + ["md-summit"] = 0xf0786, + ["md-sun_clock"] = 0xf1a77, + ["md-sun_clock_outline"] = 0xf1a78, + ["md-sun_compass"] = 0xf19a5, + ["md-sun_snowflake"] = 0xf1796, + ["md-sun_snowflake_variant"] = 0xf1a79, + ["md-sun_thermometer"] = 0xf18d6, + ["md-sun_thermometer_outline"] = 0xf18d7, + ["md-sun_wireless"] = 0xf17fe, + ["md-sun_wireless_outline"] = 0xf17ff, + ["md-sunglasses"] = 0xf04e0, + ["md-surfing"] = 0xf1746, + ["md-surround_sound"] = 0xf05c5, + ["md-surround_sound_2_0"] = 0xf07f0, + ["md-surround_sound_2_1"] = 0xf1729, + ["md-surround_sound_3_1"] = 0xf07f1, + ["md-surround_sound_5_1"] = 0xf07f2, + ["md-surround_sound_5_1_2"] = 0xf172a, + ["md-surround_sound_7_1"] = 0xf07f3, + ["md-svg"] = 0xf0721, + ["md-swap_horizontal"] = 0xf04e1, + ["md-swap_horizontal_bold"] = 0xf0bcd, + ["md-swap_horizontal_circle"] = 0xf0fe1, + ["md-swap_horizontal_circle_outline"] = 0xf0fe2, + ["md-swap_horizontal_variant"] = 0xf08c1, + ["md-swap_vertical"] = 0xf04e2, + ["md-swap_vertical_bold"] = 0xf0bce, + ["md-swap_vertical_circle"] = 0xf0fe3, + ["md-swap_vertical_circle_outline"] = 0xf0fe4, + ["md-swap_vertical_variant"] = 0xf08c2, + ["md-swim"] = 0xf04e3, + ["md-switch"] = 0xf04e4, + ["md-sword"] = 0xf04e5, + ["md-sword_cross"] = 0xf0787, + ["md-syllabary_hangul"] = 0xf1333, + ["md-syllabary_hiragana"] = 0xf1334, + ["md-syllabary_katakana"] = 0xf1335, + ["md-syllabary_katakana_halfwidth"] = 0xf1336, + ["md-symbol"] = 0xf1501, + ["md-symfony"] = 0xf0ae6, + ["md-sync"] = 0xf04e6, + ["md-sync_alert"] = 0xf04e7, + ["md-sync_circle"] = 0xf1378, + ["md-sync_off"] = 0xf04e8, + ["md-tab"] = 0xf04e9, + ["md-tab_minus"] = 0xf0b4b, + ["md-tab_plus"] = 0xf075c, + ["md-tab_remove"] = 0xf0b4c, + ["md-tab_search"] = 0xf199e, + ["md-tab_unselected"] = 0xf04ea, + ["md-table"] = 0xf04eb, + ["md-table_account"] = 0xf13b9, + ["md-table_alert"] = 0xf13ba, + ["md-table_arrow_down"] = 0xf13bb, + ["md-table_arrow_left"] = 0xf13bc, + ["md-table_arrow_right"] = 0xf13bd, + ["md-table_arrow_up"] = 0xf13be, + ["md-table_border"] = 0xf0a18, + ["md-table_cancel"] = 0xf13bf, + ["md-table_chair"] = 0xf1061, + ["md-table_check"] = 0xf13c0, + ["md-table_clock"] = 0xf13c1, + ["md-table_cog"] = 0xf13c2, + ["md-table_column"] = 0xf0835, + ["md-table_column_plus_after"] = 0xf04ec, + ["md-table_column_plus_before"] = 0xf04ed, + ["md-table_column_remove"] = 0xf04ee, + ["md-table_column_width"] = 0xf04ef, + ["md-table_edit"] = 0xf04f0, + ["md-table_eye"] = 0xf1094, + ["md-table_eye_off"] = 0xf13c3, + ["md-table_furniture"] = 0xf05bc, + ["md-table_headers_eye"] = 0xf121d, + ["md-table_headers_eye_off"] = 0xf121e, + ["md-table_heart"] = 0xf13c4, + ["md-table_key"] = 0xf13c5, + ["md-table_large"] = 0xf04f1, + ["md-table_large_plus"] = 0xf0f87, + ["md-table_large_remove"] = 0xf0f88, + ["md-table_lock"] = 0xf13c6, + ["md-table_merge_cells"] = 0xf09a6, + ["md-table_minus"] = 0xf13c7, + ["md-table_multiple"] = 0xf13c8, + ["md-table_network"] = 0xf13c9, + ["md-table_of_contents"] = 0xf0836, + ["md-table_off"] = 0xf13ca, + ["md-table_picnic"] = 0xf1743, + ["md-table_pivot"] = 0xf183c, + ["md-table_plus"] = 0xf0a75, + ["md-table_refresh"] = 0xf13a0, + ["md-table_remove"] = 0xf0a76, + ["md-table_row"] = 0xf0837, + ["md-table_row_height"] = 0xf04f2, + ["md-table_row_plus_after"] = 0xf04f3, + ["md-table_row_plus_before"] = 0xf04f4, + ["md-table_row_remove"] = 0xf04f5, + ["md-table_search"] = 0xf090f, + ["md-table_settings"] = 0xf0838, + ["md-table_split_cell"] = 0xf142a, + ["md-table_star"] = 0xf13cb, + ["md-table_sync"] = 0xf13a1, + ["md-table_tennis"] = 0xf0e68, + ["md-tablet"] = 0xf04f6, + ["md-tablet_android"] = 0xf04f7, + ["md-tablet_cellphone"] = 0xf09a7, + ["md-tablet_dashboard"] = 0xf0ece, + ["md-taco"] = 0xf0762, + ["md-tag"] = 0xf04f9, + ["md-tag_arrow_down"] = 0xf172b, + ["md-tag_arrow_down_outline"] = 0xf172c, + ["md-tag_arrow_left"] = 0xf172d, + ["md-tag_arrow_left_outline"] = 0xf172e, + ["md-tag_arrow_right"] = 0xf172f, + ["md-tag_arrow_right_outline"] = 0xf1730, + ["md-tag_arrow_up"] = 0xf1731, + ["md-tag_arrow_up_outline"] = 0xf1732, + ["md-tag_check"] = 0xf1a7a, + ["md-tag_check_outline"] = 0xf1a7b, + ["md-tag_faces"] = 0xf04fa, + ["md-tag_heart"] = 0xf068b, + ["md-tag_heart_outline"] = 0xf0bcf, + ["md-tag_minus"] = 0xf0910, + ["md-tag_minus_outline"] = 0xf121f, + ["md-tag_multiple"] = 0xf04fb, + ["md-tag_multiple_outline"] = 0xf12f7, + ["md-tag_off"] = 0xf1220, + ["md-tag_off_outline"] = 0xf1221, + ["md-tag_outline"] = 0xf04fc, + ["md-tag_plus"] = 0xf0722, + ["md-tag_plus_outline"] = 0xf1222, + ["md-tag_remove"] = 0xf0723, + ["md-tag_remove_outline"] = 0xf1223, + ["md-tag_search"] = 0xf1907, + ["md-tag_search_outline"] = 0xf1908, + ["md-tag_text"] = 0xf1224, + ["md-tag_text_outline"] = 0xf04fd, + ["md-tailwind"] = 0xf13ff, + ["md-tally_mark_1"] = 0xf1abc, + ["md-tally_mark_2"] = 0xf1abd, + ["md-tally_mark_3"] = 0xf1abe, + ["md-tally_mark_4"] = 0xf1abf, + ["md-tally_mark_5"] = 0xf1ac0, + ["md-tangram"] = 0xf04f8, + ["md-tank"] = 0xf0d3a, + ["md-tanker_truck"] = 0xf0fe5, + ["md-tape_drive"] = 0xf16df, + ["md-tape_measure"] = 0xf0b4d, + ["md-target"] = 0xf04fe, + ["md-target_account"] = 0xf0bd0, + ["md-target_variant"] = 0xf0a77, + ["md-taxi"] = 0xf04ff, + ["md-tea"] = 0xf0d9e, + ["md-tea_outline"] = 0xf0d9f, + ["md-teamviewer"] = 0xf0500, + ["md-teddy_bear"] = 0xf18fb, + ["md-telescope"] = 0xf0b4e, + ["md-television"] = 0xf0502, + ["md-television_ambient_light"] = 0xf1356, + ["md-television_box"] = 0xf0839, + ["md-television_classic"] = 0xf07f4, + ["md-television_classic_off"] = 0xf083a, + ["md-television_guide"] = 0xf0503, + ["md-television_off"] = 0xf083b, + ["md-television_pause"] = 0xf0f89, + ["md-television_play"] = 0xf0ecf, + ["md-television_shimmer"] = 0xf1110, + ["md-television_stop"] = 0xf0f8a, + ["md-temperature_celsius"] = 0xf0504, + ["md-temperature_fahrenheit"] = 0xf0505, + ["md-temperature_kelvin"] = 0xf0506, + ["md-tennis"] = 0xf0da0, + ["md-tennis_ball"] = 0xf0507, + ["md-tent"] = 0xf0508, + ["md-terraform"] = 0xf1062, + ["md-test_tube"] = 0xf0668, + ["md-test_tube_empty"] = 0xf0911, + ["md-test_tube_off"] = 0xf0912, + ["md-text"] = 0xf09a8, + ["md-text_account"] = 0xf1570, + ["md-text_box"] = 0xf021a, + ["md-text_box_check"] = 0xf0ea6, + ["md-text_box_check_outline"] = 0xf0ea7, + ["md-text_box_edit"] = 0xf1a7c, + ["md-text_box_edit_outline"] = 0xf1a7d, + ["md-text_box_minus"] = 0xf0ea8, + ["md-text_box_minus_outline"] = 0xf0ea9, + ["md-text_box_multiple"] = 0xf0ab7, + ["md-text_box_multiple_outline"] = 0xf0ab8, + ["md-text_box_outline"] = 0xf09ed, + ["md-text_box_plus"] = 0xf0eaa, + ["md-text_box_plus_outline"] = 0xf0eab, + ["md-text_box_remove"] = 0xf0eac, + ["md-text_box_remove_outline"] = 0xf0ead, + ["md-text_box_search"] = 0xf0eae, + ["md-text_box_search_outline"] = 0xf0eaf, + ["md-text_long"] = 0xf09aa, + ["md-text_recognition"] = 0xf113d, + ["md-text_search"] = 0xf13b8, + ["md-text_search_variant"] = 0xf1a7e, + ["md-text_shadow"] = 0xf0669, + ["md-text_short"] = 0xf09a9, + ["md-text_to_speech"] = 0xf050a, + ["md-text_to_speech_off"] = 0xf050b, + ["md-texture"] = 0xf050c, + ["md-texture_box"] = 0xf0fe6, + ["md-theater"] = 0xf050d, + ["md-theme_light_dark"] = 0xf050e, + ["md-thermometer"] = 0xf050f, + ["md-thermometer_alert"] = 0xf0e01, + ["md-thermometer_bluetooth"] = 0xf1895, + ["md-thermometer_check"] = 0xf1a7f, + ["md-thermometer_chevron_down"] = 0xf0e02, + ["md-thermometer_chevron_up"] = 0xf0e03, + ["md-thermometer_high"] = 0xf10c2, + ["md-thermometer_lines"] = 0xf0510, + ["md-thermometer_low"] = 0xf10c3, + ["md-thermometer_minus"] = 0xf0e04, + ["md-thermometer_off"] = 0xf1531, + ["md-thermometer_plus"] = 0xf0e05, + ["md-thermometer_water"] = 0xf1a80, + ["md-thermostat"] = 0xf0393, + ["md-thermostat_box"] = 0xf0891, + ["md-thought_bubble"] = 0xf07f6, + ["md-thought_bubble_outline"] = 0xf07f7, + ["md-thumb_down"] = 0xf0511, + ["md-thumb_down_outline"] = 0xf0512, + ["md-thumb_up"] = 0xf0513, + ["md-thumb_up_outline"] = 0xf0514, + ["md-thumbs_up_down"] = 0xf0515, + ["md-thumbs_up_down_outline"] = 0xf1914, + ["md-ticket"] = 0xf0516, + ["md-ticket_account"] = 0xf0517, + ["md-ticket_confirmation"] = 0xf0518, + ["md-ticket_confirmation_outline"] = 0xf13aa, + ["md-ticket_outline"] = 0xf0913, + ["md-ticket_percent"] = 0xf0724, + ["md-ticket_percent_outline"] = 0xf142b, + ["md-tie"] = 0xf0519, + ["md-tilde"] = 0xf0725, + ["md-tilde_off"] = 0xf18f3, + ["md-timelapse"] = 0xf051a, + ["md-timeline"] = 0xf0bd1, + ["md-timeline_alert"] = 0xf0f95, + ["md-timeline_alert_outline"] = 0xf0f98, + ["md-timeline_check"] = 0xf1532, + ["md-timeline_check_outline"] = 0xf1533, + ["md-timeline_clock"] = 0xf11fb, + ["md-timeline_clock_outline"] = 0xf11fc, + ["md-timeline_help"] = 0xf0f99, + ["md-timeline_help_outline"] = 0xf0f9a, + ["md-timeline_minus"] = 0xf1534, + ["md-timeline_minus_outline"] = 0xf1535, + ["md-timeline_outline"] = 0xf0bd2, + ["md-timeline_plus"] = 0xf0f96, + ["md-timeline_plus_outline"] = 0xf0f97, + ["md-timeline_remove"] = 0xf1536, + ["md-timeline_remove_outline"] = 0xf1537, + ["md-timeline_text"] = 0xf0bd3, + ["md-timeline_text_outline"] = 0xf0bd4, + ["md-timer"] = 0xf13ab, + ["md-timer_10"] = 0xf051c, + ["md-timer_3"] = 0xf051d, + ["md-timer_alert"] = 0xf1acc, + ["md-timer_alert_outline"] = 0xf1acd, + ["md-timer_cancel"] = 0xf1ace, + ["md-timer_cancel_outline"] = 0xf1acf, + ["md-timer_check"] = 0xf1ad0, + ["md-timer_check_outline"] = 0xf1ad1, + ["md-timer_cog"] = 0xf1925, + ["md-timer_cog_outline"] = 0xf1926, + ["md-timer_edit"] = 0xf1ad2, + ["md-timer_edit_outline"] = 0xf1ad3, + ["md-timer_lock"] = 0xf1ad4, + ["md-timer_lock_open"] = 0xf1ad5, + ["md-timer_lock_open_outline"] = 0xf1ad6, + ["md-timer_lock_outline"] = 0xf1ad7, + ["md-timer_marker"] = 0xf1ad8, + ["md-timer_marker_outline"] = 0xf1ad9, + ["md-timer_minus"] = 0xf1ada, + ["md-timer_minus_outline"] = 0xf1adb, + ["md-timer_music"] = 0xf1adc, + ["md-timer_music_outline"] = 0xf1add, + ["md-timer_off"] = 0xf13ac, + ["md-timer_off_outline"] = 0xf051e, + ["md-timer_outline"] = 0xf051b, + ["md-timer_pause"] = 0xf1ade, + ["md-timer_pause_outline"] = 0xf1adf, + ["md-timer_play"] = 0xf1ae0, + ["md-timer_play_outline"] = 0xf1ae1, + ["md-timer_plus"] = 0xf1ae2, + ["md-timer_plus_outline"] = 0xf1ae3, + ["md-timer_refresh"] = 0xf1ae4, + ["md-timer_refresh_outline"] = 0xf1ae5, + ["md-timer_remove"] = 0xf1ae6, + ["md-timer_remove_outline"] = 0xf1ae7, + ["md-timer_sand"] = 0xf051f, + ["md-timer_sand_complete"] = 0xf199f, + ["md-timer_sand_empty"] = 0xf06ad, + ["md-timer_sand_full"] = 0xf078c, + ["md-timer_sand_paused"] = 0xf19a0, + ["md-timer_settings"] = 0xf1923, + ["md-timer_settings_outline"] = 0xf1924, + ["md-timer_star"] = 0xf1ae8, + ["md-timer_star_outline"] = 0xf1ae9, + ["md-timer_stop"] = 0xf1aea, + ["md-timer_stop_outline"] = 0xf1aeb, + ["md-timer_sync"] = 0xf1aec, + ["md-timer_sync_outline"] = 0xf1aed, + ["md-timetable"] = 0xf0520, + ["md-tire"] = 0xf1896, + ["md-toaster"] = 0xf1063, + ["md-toaster_off"] = 0xf11b7, + ["md-toaster_oven"] = 0xf0cd3, + ["md-toggle_switch"] = 0xf0521, + ["md-toggle_switch_off"] = 0xf0522, + ["md-toggle_switch_off_outline"] = 0xf0a19, + ["md-toggle_switch_outline"] = 0xf0a1a, + ["md-toggle_switch_variant"] = 0xf1a25, + ["md-toggle_switch_variant_off"] = 0xf1a26, + ["md-toilet"] = 0xf09ab, + ["md-toolbox"] = 0xf09ac, + ["md-toolbox_outline"] = 0xf09ad, + ["md-tools"] = 0xf1064, + ["md-tooltip"] = 0xf0523, + ["md-tooltip_account"] = 0xf000c, + ["md-tooltip_cellphone"] = 0xf183b, + ["md-tooltip_check"] = 0xf155c, + ["md-tooltip_check_outline"] = 0xf155d, + ["md-tooltip_edit"] = 0xf0524, + ["md-tooltip_edit_outline"] = 0xf12c5, + ["md-tooltip_image"] = 0xf0525, + ["md-tooltip_image_outline"] = 0xf0bd5, + ["md-tooltip_minus"] = 0xf155e, + ["md-tooltip_minus_outline"] = 0xf155f, + ["md-tooltip_outline"] = 0xf0526, + ["md-tooltip_plus"] = 0xf0bd6, + ["md-tooltip_plus_outline"] = 0xf0527, + ["md-tooltip_remove"] = 0xf1560, + ["md-tooltip_remove_outline"] = 0xf1561, + ["md-tooltip_text"] = 0xf0528, + ["md-tooltip_text_outline"] = 0xf0bd7, + ["md-tooth"] = 0xf08c3, + ["md-tooth_outline"] = 0xf0529, + ["md-toothbrush"] = 0xf1129, + ["md-toothbrush_electric"] = 0xf112c, + ["md-toothbrush_paste"] = 0xf112a, + ["md-torch"] = 0xf1606, + ["md-tortoise"] = 0xf0d3b, + ["md-toslink"] = 0xf12b8, + ["md-tournament"] = 0xf09ae, + ["md-tow_truck"] = 0xf083c, + ["md-tower_beach"] = 0xf0681, + ["md-tower_fire"] = 0xf0682, + ["md-town_hall"] = 0xf1875, + ["md-toy_brick"] = 0xf1288, + ["md-toy_brick_marker"] = 0xf1289, + ["md-toy_brick_marker_outline"] = 0xf128a, + ["md-toy_brick_minus"] = 0xf128b, + ["md-toy_brick_minus_outline"] = 0xf128c, + ["md-toy_brick_outline"] = 0xf128d, + ["md-toy_brick_plus"] = 0xf128e, + ["md-toy_brick_plus_outline"] = 0xf128f, + ["md-toy_brick_remove"] = 0xf1290, + ["md-toy_brick_remove_outline"] = 0xf1291, + ["md-toy_brick_search"] = 0xf1292, + ["md-toy_brick_search_outline"] = 0xf1293, + ["md-track_light"] = 0xf0914, + ["md-trackpad"] = 0xf07f8, + ["md-trackpad_lock"] = 0xf0933, + ["md-tractor"] = 0xf0892, + ["md-tractor_variant"] = 0xf14c4, + ["md-trademark"] = 0xf0a78, + ["md-traffic_cone"] = 0xf137c, + ["md-traffic_light"] = 0xf052b, + ["md-traffic_light_outline"] = 0xf182a, + ["md-train"] = 0xf052c, + ["md-train_car"] = 0xf0bd8, + ["md-train_car_passenger"] = 0xf1733, + ["md-train_car_passenger_door"] = 0xf1734, + ["md-train_car_passenger_door_open"] = 0xf1735, + ["md-train_car_passenger_variant"] = 0xf1736, + ["md-train_variant"] = 0xf08c4, + ["md-tram"] = 0xf052d, + ["md-tram_side"] = 0xf0fe7, + ["md-transcribe"] = 0xf052e, + ["md-transcribe_close"] = 0xf052f, + ["md-transfer"] = 0xf1065, + ["md-transfer_down"] = 0xf0da1, + ["md-transfer_left"] = 0xf0da2, + ["md-transfer_right"] = 0xf0530, + ["md-transfer_up"] = 0xf0da3, + ["md-transit_connection"] = 0xf0d3c, + ["md-transit_connection_horizontal"] = 0xf1546, + ["md-transit_connection_variant"] = 0xf0d3d, + ["md-transit_detour"] = 0xf0f8b, + ["md-transit_skip"] = 0xf1515, + ["md-transit_transfer"] = 0xf06ae, + ["md-transition"] = 0xf0915, + ["md-transition_masked"] = 0xf0916, + ["md-translate"] = 0xf05ca, + ["md-translate_off"] = 0xf0e06, + ["md-transmission_tower"] = 0xf0d3e, + ["md-transmission_tower_export"] = 0xf192c, + ["md-transmission_tower_import"] = 0xf192d, + ["md-transmission_tower_off"] = 0xf19dd, + ["md-trash_can"] = 0xf0a79, + ["md-trash_can_outline"] = 0xf0a7a, + ["md-tray"] = 0xf1294, + ["md-tray_alert"] = 0xf1295, + ["md-tray_arrow_down"] = 0xf0120, + ["md-tray_arrow_up"] = 0xf011d, + ["md-tray_full"] = 0xf1296, + ["md-tray_minus"] = 0xf1297, + ["md-tray_plus"] = 0xf1298, + ["md-tray_remove"] = 0xf1299, + ["md-treasure_chest"] = 0xf0726, + ["md-tree"] = 0xf0531, + ["md-tree_outline"] = 0xf0e69, + ["md-trello"] = 0xf0532, + ["md-trending_down"] = 0xf0533, + ["md-trending_neutral"] = 0xf0534, + ["md-trending_up"] = 0xf0535, + ["md-triangle"] = 0xf0536, + ["md-triangle_outline"] = 0xf0537, + ["md-triangle_small_down"] = 0xf1a09, + ["md-triangle_small_up"] = 0xf1a0a, + ["md-triangle_wave"] = 0xf147c, + ["md-triforce"] = 0xf0bd9, + ["md-trophy"] = 0xf0538, + ["md-trophy_award"] = 0xf0539, + ["md-trophy_broken"] = 0xf0da4, + ["md-trophy_outline"] = 0xf053a, + ["md-trophy_variant"] = 0xf053b, + ["md-trophy_variant_outline"] = 0xf053c, + ["md-truck"] = 0xf053d, + ["md-truck_alert"] = 0xf19de, + ["md-truck_alert_outline"] = 0xf19df, + ["md-truck_cargo_container"] = 0xf18d8, + ["md-truck_check"] = 0xf0cd4, + ["md-truck_check_outline"] = 0xf129a, + ["md-truck_delivery"] = 0xf053e, + ["md-truck_delivery_outline"] = 0xf129b, + ["md-truck_fast"] = 0xf0788, + ["md-truck_fast_outline"] = 0xf129c, + ["md-truck_flatbed"] = 0xf1891, + ["md-truck_minus"] = 0xf19ae, + ["md-truck_minus_outline"] = 0xf19bd, + ["md-truck_outline"] = 0xf129d, + ["md-truck_plus"] = 0xf19ad, + ["md-truck_plus_outline"] = 0xf19bc, + ["md-truck_remove"] = 0xf19af, + ["md-truck_remove_outline"] = 0xf19be, + ["md-truck_snowflake"] = 0xf19a6, + ["md-truck_trailer"] = 0xf0727, + ["md-trumpet"] = 0xf1096, + ["md-tshirt_crew"] = 0xf0a7b, + ["md-tshirt_crew_outline"] = 0xf053f, + ["md-tshirt_v"] = 0xf0a7c, + ["md-tshirt_v_outline"] = 0xf0540, + ["md-tsunami"] = 0xf1a81, + ["md-tumble_dryer"] = 0xf0917, + ["md-tumble_dryer_alert"] = 0xf11ba, + ["md-tumble_dryer_off"] = 0xf11bb, + ["md-tune"] = 0xf062e, + ["md-tune_variant"] = 0xf1542, + ["md-tune_vertical"] = 0xf066a, + ["md-tune_vertical_variant"] = 0xf1543, + ["md-tunnel"] = 0xf183d, + ["md-tunnel_outline"] = 0xf183e, + ["md-turbine"] = 0xf1a82, + ["md-turkey"] = 0xf171b, + ["md-turnstile"] = 0xf0cd5, + ["md-turnstile_outline"] = 0xf0cd6, + ["md-turtle"] = 0xf0cd7, + ["md-twitch"] = 0xf0543, + ["md-twitter"] = 0xf0544, + ["md-two_factor_authentication"] = 0xf09af, + ["md-typewriter"] = 0xf0f2d, + ["md-ubisoft"] = 0xf0bda, + ["md-ubuntu"] = 0xf0548, + ["md-ufo"] = 0xf10c4, + ["md-ufo_outline"] = 0xf10c5, + ["md-ultra_high_definition"] = 0xf07f9, + ["md-umbraco"] = 0xf0549, + ["md-umbrella"] = 0xf054a, + ["md-umbrella_beach"] = 0xf188a, + ["md-umbrella_beach_outline"] = 0xf188b, + ["md-umbrella_closed"] = 0xf09b0, + ["md-umbrella_closed_outline"] = 0xf13e2, + ["md-umbrella_closed_variant"] = 0xf13e1, + ["md-umbrella_outline"] = 0xf054b, + ["md-undo"] = 0xf054c, + ["md-undo_variant"] = 0xf054d, + ["md-unfold_less_horizontal"] = 0xf054e, + ["md-unfold_less_vertical"] = 0xf0760, + ["md-unfold_more_horizontal"] = 0xf054f, + ["md-unfold_more_vertical"] = 0xf0761, + ["md-ungroup"] = 0xf0550, + ["md-unicode"] = 0xf0ed0, + ["md-unicorn"] = 0xf15c2, + ["md-unicorn_variant"] = 0xf15c3, + ["md-unicycle"] = 0xf15e5, + ["md-unity"] = 0xf06af, + ["md-unreal"] = 0xf09b1, + ["md-update"] = 0xf06b0, + ["md-upload"] = 0xf0552, + ["md-upload_lock"] = 0xf1373, + ["md-upload_lock_outline"] = 0xf1374, + ["md-upload_multiple"] = 0xf083d, + ["md-upload_network"] = 0xf06f6, + ["md-upload_network_outline"] = 0xf0cd8, + ["md-upload_off"] = 0xf10c6, + ["md-upload_off_outline"] = 0xf10c7, + ["md-upload_outline"] = 0xf0e07, + ["md-usb"] = 0xf0553, + ["md-usb_flash_drive"] = 0xf129e, + ["md-usb_flash_drive_outline"] = 0xf129f, + ["md-usb_port"] = 0xf11f0, + ["md-vacuum"] = 0xf19a1, + ["md-vacuum_outline"] = 0xf19a2, + ["md-valve"] = 0xf1066, + ["md-valve_closed"] = 0xf1067, + ["md-valve_open"] = 0xf1068, + ["md-van_passenger"] = 0xf07fa, + ["md-van_utility"] = 0xf07fb, + ["md-vanish"] = 0xf07fc, + ["md-vanish_quarter"] = 0xf1554, + ["md-vanity_light"] = 0xf11e1, + ["md-variable"] = 0xf0ae7, + ["md-variable_box"] = 0xf1111, + ["md-vector_arrange_above"] = 0xf0554, + ["md-vector_arrange_below"] = 0xf0555, + ["md-vector_bezier"] = 0xf0ae8, + ["md-vector_circle"] = 0xf0556, + ["md-vector_circle_variant"] = 0xf0557, + ["md-vector_combine"] = 0xf0558, + ["md-vector_curve"] = 0xf0559, + ["md-vector_difference"] = 0xf055a, + ["md-vector_difference_ab"] = 0xf055b, + ["md-vector_difference_ba"] = 0xf055c, + ["md-vector_ellipse"] = 0xf0893, + ["md-vector_intersection"] = 0xf055d, + ["md-vector_line"] = 0xf055e, + ["md-vector_link"] = 0xf0fe8, + ["md-vector_point"] = 0xf055f, + ["md-vector_polygon"] = 0xf0560, + ["md-vector_polygon_variant"] = 0xf1856, + ["md-vector_polyline"] = 0xf0561, + ["md-vector_polyline_edit"] = 0xf1225, + ["md-vector_polyline_minus"] = 0xf1226, + ["md-vector_polyline_plus"] = 0xf1227, + ["md-vector_polyline_remove"] = 0xf1228, + ["md-vector_radius"] = 0xf074a, + ["md-vector_rectangle"] = 0xf05c6, + ["md-vector_selection"] = 0xf0562, + ["md-vector_square"] = 0xf0001, + ["md-vector_square_close"] = 0xf1857, + ["md-vector_square_edit"] = 0xf18d9, + ["md-vector_square_minus"] = 0xf18da, + ["md-vector_square_open"] = 0xf1858, + ["md-vector_square_plus"] = 0xf18db, + ["md-vector_square_remove"] = 0xf18dc, + ["md-vector_triangle"] = 0xf0563, + ["md-vector_union"] = 0xf0564, + ["md-vhs"] = 0xf0a1b, + ["md-vibrate"] = 0xf0566, + ["md-vibrate_off"] = 0xf0cd9, + ["md-video"] = 0xf0567, + ["md-video_2d"] = 0xf1a1c, + ["md-video_3d"] = 0xf07fd, + ["md-video_3d_off"] = 0xf13d9, + ["md-video_3d_variant"] = 0xf0ed1, + ["md-video_4k_box"] = 0xf083e, + ["md-video_account"] = 0xf0919, + ["md-video_box"] = 0xf00fd, + ["md-video_box_off"] = 0xf00fe, + ["md-video_check"] = 0xf1069, + ["md-video_check_outline"] = 0xf106a, + ["md-video_high_definition"] = 0xf152e, + ["md-video_image"] = 0xf091a, + ["md-video_input_antenna"] = 0xf083f, + ["md-video_input_component"] = 0xf0840, + ["md-video_input_hdmi"] = 0xf0841, + ["md-video_input_scart"] = 0xf0f8c, + ["md-video_input_svideo"] = 0xf0842, + ["md-video_marker"] = 0xf19a9, + ["md-video_marker_outline"] = 0xf19aa, + ["md-video_minus"] = 0xf09b2, + ["md-video_minus_outline"] = 0xf02ba, + ["md-video_off"] = 0xf0568, + ["md-video_off_outline"] = 0xf0bdb, + ["md-video_outline"] = 0xf0bdc, + ["md-video_plus"] = 0xf09b3, + ["md-video_plus_outline"] = 0xf01d3, + ["md-video_stabilization"] = 0xf091b, + ["md-video_switch"] = 0xf0569, + ["md-video_switch_outline"] = 0xf0790, + ["md-video_vintage"] = 0xf0a1c, + ["md-video_wireless"] = 0xf0ed2, + ["md-video_wireless_outline"] = 0xf0ed3, + ["md-view_agenda"] = 0xf056a, + ["md-view_agenda_outline"] = 0xf11d8, + ["md-view_array"] = 0xf056b, + ["md-view_array_outline"] = 0xf1485, + ["md-view_carousel"] = 0xf056c, + ["md-view_carousel_outline"] = 0xf1486, + ["md-view_column"] = 0xf056d, + ["md-view_column_outline"] = 0xf1487, + ["md-view_comfy"] = 0xf0e6a, + ["md-view_comfy_outline"] = 0xf1488, + ["md-view_compact"] = 0xf0e6b, + ["md-view_compact_outline"] = 0xf0e6c, + ["md-view_dashboard"] = 0xf056e, + ["md-view_dashboard_edit"] = 0xf1947, + ["md-view_dashboard_edit_outline"] = 0xf1948, + ["md-view_dashboard_outline"] = 0xf0a1d, + ["md-view_dashboard_variant"] = 0xf0843, + ["md-view_dashboard_variant_outline"] = 0xf1489, + ["md-view_day"] = 0xf056f, + ["md-view_day_outline"] = 0xf148a, + ["md-view_gallery"] = 0xf1888, + ["md-view_gallery_outline"] = 0xf1889, + ["md-view_grid"] = 0xf0570, + ["md-view_grid_outline"] = 0xf11d9, + ["md-view_grid_plus"] = 0xf0f8d, + ["md-view_grid_plus_outline"] = 0xf11da, + ["md-view_headline"] = 0xf0571, + ["md-view_list"] = 0xf0572, + ["md-view_list_outline"] = 0xf148b, + ["md-view_module"] = 0xf0573, + ["md-view_module_outline"] = 0xf148c, + ["md-view_parallel"] = 0xf0728, + ["md-view_parallel_outline"] = 0xf148d, + ["md-view_quilt"] = 0xf0574, + ["md-view_quilt_outline"] = 0xf148e, + ["md-view_sequential"] = 0xf0729, + ["md-view_sequential_outline"] = 0xf148f, + ["md-view_split_horizontal"] = 0xf0bcb, + ["md-view_split_vertical"] = 0xf0bcc, + ["md-view_stream"] = 0xf0575, + ["md-view_stream_outline"] = 0xf1490, + ["md-view_week"] = 0xf0576, + ["md-view_week_outline"] = 0xf1491, + ["md-vimeo"] = 0xf0577, + ["md-violin"] = 0xf060f, + ["md-virtual_reality"] = 0xf0894, + ["md-virus"] = 0xf13b6, + ["md-virus_off"] = 0xf18e1, + ["md-virus_off_outline"] = 0xf18e2, + ["md-virus_outline"] = 0xf13b7, + ["md-vlc"] = 0xf057c, + ["md-voicemail"] = 0xf057d, + ["md-volcano"] = 0xf1a83, + ["md-volcano_outline"] = 0xf1a84, + ["md-volleyball"] = 0xf09b4, + ["md-volume_high"] = 0xf057e, + ["md-volume_low"] = 0xf057f, + ["md-volume_medium"] = 0xf0580, + ["md-volume_minus"] = 0xf075e, + ["md-volume_mute"] = 0xf075f, + ["md-volume_off"] = 0xf0581, + ["md-volume_plus"] = 0xf075d, + ["md-volume_source"] = 0xf1120, + ["md-volume_variant_off"] = 0xf0e08, + ["md-volume_vibrate"] = 0xf1121, + ["md-vote"] = 0xf0a1f, + ["md-vote_outline"] = 0xf0a20, + ["md-vpn"] = 0xf0582, + ["md-vuejs"] = 0xf0844, + ["md-vuetify"] = 0xf0e6d, + ["md-walk"] = 0xf0583, + ["md-wall"] = 0xf07fe, + ["md-wall_fire"] = 0xf1a11, + ["md-wall_sconce"] = 0xf091c, + ["md-wall_sconce_flat"] = 0xf091d, + ["md-wall_sconce_flat_outline"] = 0xf17c9, + ["md-wall_sconce_flat_variant"] = 0xf041c, + ["md-wall_sconce_flat_variant_outline"] = 0xf17ca, + ["md-wall_sconce_outline"] = 0xf17cb, + ["md-wall_sconce_round"] = 0xf0748, + ["md-wall_sconce_round_outline"] = 0xf17cc, + ["md-wall_sconce_round_variant"] = 0xf091e, + ["md-wall_sconce_round_variant_outline"] = 0xf17cd, + ["md-wallet"] = 0xf0584, + ["md-wallet_giftcard"] = 0xf0585, + ["md-wallet_membership"] = 0xf0586, + ["md-wallet_outline"] = 0xf0bdd, + ["md-wallet_plus"] = 0xf0f8e, + ["md-wallet_plus_outline"] = 0xf0f8f, + ["md-wallet_travel"] = 0xf0587, + ["md-wallpaper"] = 0xf0e09, + ["md-wan"] = 0xf0588, + ["md-wardrobe"] = 0xf0f90, + ["md-wardrobe_outline"] = 0xf0f91, + ["md-warehouse"] = 0xf0f81, + ["md-washing_machine"] = 0xf072a, + ["md-washing_machine_alert"] = 0xf11bc, + ["md-washing_machine_off"] = 0xf11bd, + ["md-watch"] = 0xf0589, + ["md-watch_export"] = 0xf058a, + ["md-watch_export_variant"] = 0xf0895, + ["md-watch_import"] = 0xf058b, + ["md-watch_import_variant"] = 0xf0896, + ["md-watch_variant"] = 0xf0897, + ["md-watch_vibrate"] = 0xf06b1, + ["md-watch_vibrate_off"] = 0xf0cda, + ["md-water"] = 0xf058c, + ["md-water_alert"] = 0xf1502, + ["md-water_alert_outline"] = 0xf1503, + ["md-water_boiler"] = 0xf0f92, + ["md-water_boiler_alert"] = 0xf11b3, + ["md-water_boiler_off"] = 0xf11b4, + ["md-water_check"] = 0xf1504, + ["md-water_check_outline"] = 0xf1505, + ["md-water_circle"] = 0xf1806, + ["md-water_minus"] = 0xf1506, + ["md-water_minus_outline"] = 0xf1507, + ["md-water_off"] = 0xf058d, + ["md-water_off_outline"] = 0xf1508, + ["md-water_opacity"] = 0xf1855, + ["md-water_outline"] = 0xf0e0a, + ["md-water_percent"] = 0xf058e, + ["md-water_percent_alert"] = 0xf1509, + ["md-water_plus"] = 0xf150a, + ["md-water_plus_outline"] = 0xf150b, + ["md-water_polo"] = 0xf12a0, + ["md-water_pump"] = 0xf058f, + ["md-water_pump_off"] = 0xf0f93, + ["md-water_remove"] = 0xf150c, + ["md-water_remove_outline"] = 0xf150d, + ["md-water_sync"] = 0xf17c6, + ["md-water_thermometer"] = 0xf1a85, + ["md-water_thermometer_outline"] = 0xf1a86, + ["md-water_well"] = 0xf106b, + ["md-water_well_outline"] = 0xf106c, + ["md-waterfall"] = 0xf1849, + ["md-watering_can"] = 0xf1481, + ["md-watering_can_outline"] = 0xf1482, + ["md-watermark"] = 0xf0612, + ["md-wave"] = 0xf0f2e, + ["md-waveform"] = 0xf147d, + ["md-waves"] = 0xf078d, + ["md-waves_arrow_left"] = 0xf1859, + ["md-waves_arrow_right"] = 0xf185a, + ["md-waves_arrow_up"] = 0xf185b, + ["md-waze"] = 0xf0bde, + ["md-weather_cloudy"] = 0xf0590, + ["md-weather_cloudy_alert"] = 0xf0f2f, + ["md-weather_cloudy_arrow_right"] = 0xf0e6e, + ["md-weather_cloudy_clock"] = 0xf18f6, + ["md-weather_fog"] = 0xf0591, + ["md-weather_hail"] = 0xf0592, + ["md-weather_hazy"] = 0xf0f30, + ["md-weather_hurricane"] = 0xf0898, + ["md-weather_lightning"] = 0xf0593, + ["md-weather_lightning_rainy"] = 0xf067e, + ["md-weather_night"] = 0xf0594, + ["md-weather_night_partly_cloudy"] = 0xf0f31, + ["md-weather_partly_cloudy"] = 0xf0595, + ["md-weather_partly_lightning"] = 0xf0f32, + ["md-weather_partly_rainy"] = 0xf0f33, + ["md-weather_partly_snowy"] = 0xf0f34, + ["md-weather_partly_snowy_rainy"] = 0xf0f35, + ["md-weather_pouring"] = 0xf0596, + ["md-weather_rainy"] = 0xf0597, + ["md-weather_snowy"] = 0xf0598, + ["md-weather_snowy_heavy"] = 0xf0f36, + ["md-weather_snowy_rainy"] = 0xf067f, + ["md-weather_sunny"] = 0xf0599, + ["md-weather_sunny_alert"] = 0xf0f37, + ["md-weather_sunny_off"] = 0xf14e4, + ["md-weather_sunset"] = 0xf059a, + ["md-weather_sunset_down"] = 0xf059b, + ["md-weather_sunset_up"] = 0xf059c, + ["md-weather_tornado"] = 0xf0f38, + ["md-weather_windy"] = 0xf059d, + ["md-weather_windy_variant"] = 0xf059e, + ["md-web"] = 0xf059f, + ["md-web_box"] = 0xf0f94, + ["md-web_cancel"] = 0xf1790, + ["md-web_check"] = 0xf0789, + ["md-web_clock"] = 0xf124a, + ["md-web_minus"] = 0xf10a0, + ["md-web_off"] = 0xf0a8e, + ["md-web_plus"] = 0xf0033, + ["md-web_refresh"] = 0xf1791, + ["md-web_remove"] = 0xf0551, + ["md-web_sync"] = 0xf1792, + ["md-webcam"] = 0xf05a0, + ["md-webcam_off"] = 0xf1737, + ["md-webhook"] = 0xf062f, + ["md-webpack"] = 0xf072b, + ["md-webrtc"] = 0xf1248, + ["md-wechat"] = 0xf0611, + ["md-weight"] = 0xf05a1, + ["md-weight_gram"] = 0xf0d3f, + ["md-weight_kilogram"] = 0xf05a2, + ["md-weight_lifter"] = 0xf115d, + ["md-weight_pound"] = 0xf09b5, + ["md-whatsapp"] = 0xf05a3, + ["md-wheel_barrow"] = 0xf14f2, + ["md-wheelchair"] = 0xf1a87, + ["md-wheelchair_accessibility"] = 0xf05a4, + ["md-whistle"] = 0xf09b6, + ["md-whistle_outline"] = 0xf12bc, + ["md-white_balance_auto"] = 0xf05a5, + ["md-white_balance_incandescent"] = 0xf05a6, + ["md-white_balance_iridescent"] = 0xf05a7, + ["md-white_balance_sunny"] = 0xf05a8, + ["md-widgets"] = 0xf072c, + ["md-widgets_outline"] = 0xf1355, + ["md-wifi"] = 0xf05a9, + ["md-wifi_alert"] = 0xf16b5, + ["md-wifi_arrow_down"] = 0xf16b6, + ["md-wifi_arrow_left"] = 0xf16b7, + ["md-wifi_arrow_left_right"] = 0xf16b8, + ["md-wifi_arrow_right"] = 0xf16b9, + ["md-wifi_arrow_up"] = 0xf16ba, + ["md-wifi_arrow_up_down"] = 0xf16bb, + ["md-wifi_cancel"] = 0xf16bc, + ["md-wifi_check"] = 0xf16bd, + ["md-wifi_cog"] = 0xf16be, + ["md-wifi_lock"] = 0xf16bf, + ["md-wifi_lock_open"] = 0xf16c0, + ["md-wifi_marker"] = 0xf16c1, + ["md-wifi_minus"] = 0xf16c2, + ["md-wifi_off"] = 0xf05aa, + ["md-wifi_plus"] = 0xf16c3, + ["md-wifi_refresh"] = 0xf16c4, + ["md-wifi_remove"] = 0xf16c5, + ["md-wifi_settings"] = 0xf16c6, + ["md-wifi_star"] = 0xf0e0b, + ["md-wifi_strength_1"] = 0xf091f, + ["md-wifi_strength_1_alert"] = 0xf0920, + ["md-wifi_strength_1_lock"] = 0xf0921, + ["md-wifi_strength_1_lock_open"] = 0xf16cb, + ["md-wifi_strength_2"] = 0xf0922, + ["md-wifi_strength_2_alert"] = 0xf0923, + ["md-wifi_strength_2_lock"] = 0xf0924, + ["md-wifi_strength_2_lock_open"] = 0xf16cc, + ["md-wifi_strength_3"] = 0xf0925, + ["md-wifi_strength_3_alert"] = 0xf0926, + ["md-wifi_strength_3_lock"] = 0xf0927, + ["md-wifi_strength_3_lock_open"] = 0xf16cd, + ["md-wifi_strength_4"] = 0xf0928, + ["md-wifi_strength_4_alert"] = 0xf0929, + ["md-wifi_strength_4_lock"] = 0xf092a, + ["md-wifi_strength_4_lock_open"] = 0xf16ce, + ["md-wifi_strength_alert_outline"] = 0xf092b, + ["md-wifi_strength_lock_open_outline"] = 0xf16cf, + ["md-wifi_strength_lock_outline"] = 0xf092c, + ["md-wifi_strength_off"] = 0xf092d, + ["md-wifi_strength_off_outline"] = 0xf092e, + ["md-wifi_strength_outline"] = 0xf092f, + ["md-wifi_sync"] = 0xf16c7, + ["md-wikipedia"] = 0xf05ac, + ["md-wind_power"] = 0xf1a88, + ["md-wind_power_outline"] = 0xf1a89, + ["md-wind_turbine"] = 0xf0da5, + ["md-wind_turbine_alert"] = 0xf19ab, + ["md-wind_turbine_check"] = 0xf19ac, + ["md-window_close"] = 0xf05ad, + ["md-window_closed"] = 0xf05ae, + ["md-window_closed_variant"] = 0xf11db, + ["md-window_maximize"] = 0xf05af, + ["md-window_minimize"] = 0xf05b0, + ["md-window_open"] = 0xf05b1, + ["md-window_open_variant"] = 0xf11dc, + ["md-window_restore"] = 0xf05b2, + ["md-window_shutter"] = 0xf111c, + ["md-window_shutter_alert"] = 0xf111d, + ["md-window_shutter_cog"] = 0xf1a8a, + ["md-window_shutter_open"] = 0xf111e, + ["md-window_shutter_settings"] = 0xf1a8b, + ["md-windsock"] = 0xf15fa, + ["md-wiper"] = 0xf0ae9, + ["md-wiper_wash"] = 0xf0da6, + ["md-wiper_wash_alert"] = 0xf18df, + ["md-wizard_hat"] = 0xf1477, + ["md-wordpress"] = 0xf05b4, + ["md-wrap"] = 0xf05b6, + ["md-wrap_disabled"] = 0xf0bdf, + ["md-wrench"] = 0xf05b7, + ["md-wrench_clock"] = 0xf19a3, + ["md-wrench_outline"] = 0xf0be0, + ["md-xamarin"] = 0xf0845, + ["md-xml"] = 0xf05c0, + ["md-xmpp"] = 0xf07ff, + ["md-yahoo"] = 0xf0b4f, + ["md-yeast"] = 0xf05c1, + ["md-yin_yang"] = 0xf0680, + ["md-yoga"] = 0xf117c, + ["md-youtube"] = 0xf05c3, + ["md-youtube_gaming"] = 0xf0848, + ["md-youtube_studio"] = 0xf0847, + ["md-youtube_subscription"] = 0xf0d40, + ["md-youtube_tv"] = 0xf0448, + ["md-yurt"] = 0xf1516, + ["md-z_wave"] = 0xf0aea, + ["md-zend"] = 0xf0aeb, + ["md-zigbee"] = 0xf0d41, + ["md-zip_box"] = 0xf05c4, + ["md-zip_box_outline"] = 0xf0ffa, + ["md-zip_disk"] = 0xf0a23, + ["md-zodiac_aquarius"] = 0xf0a7d, + ["md-zodiac_aries"] = 0xf0a7e, + ["md-zodiac_cancer"] = 0xf0a7f, + ["md-zodiac_capricorn"] = 0xf0a80, + ["md-zodiac_gemini"] = 0xf0a81, + ["md-zodiac_leo"] = 0xf0a82, + ["md-zodiac_libra"] = 0xf0a83, + ["md-zodiac_pisces"] = 0xf0a84, + ["md-zodiac_sagittarius"] = 0xf0a85, + ["md-zodiac_scorpio"] = 0xf0a86, + ["md-zodiac_taurus"] = 0xf0a87, + ["md-zodiac_virgo"] = 0xf0a88, + ["oct-accessibility"] = 0xf406, + ["oct-accessibility_inset"] = 0xf40b, + ["oct-alert"] = 0xf421, + ["oct-alert_fill"] = 0xf40c, + ["oct-apps"] = 0xf40e, + ["oct-archive"] = 0xf411, + ["oct-arrow_both"] = 0xf416, + ["oct-arrow_down"] = 0xf433, + ["oct-arrow_down_left"] = 0xf424, + ["oct-arrow_down_right"] = 0xf43e, + ["oct-arrow_left"] = 0xf434, + ["oct-arrow_right"] = 0xf432, + ["oct-arrow_switch"] = 0xf443, + ["oct-arrow_up"] = 0xf431, + ["oct-arrow_up_left"] = 0xf45c, + ["oct-arrow_up_right"] = 0xf46c, + ["oct-beaker"] = 0xf499, + ["oct-bell"] = 0xf49a, + ["oct-bell_fill"] = 0xf476, + ["oct-bell_slash"] = 0xf478, + ["oct-blocked"] = 0xf479, + ["oct-bold"] = 0xf49d, + ["oct-book"] = 0xf405, + ["oct-bookmark"] = 0xf461, + ["oct-bookmark_fill"] = 0xf47a, + ["oct-bookmark_slash"] = 0xf533, + ["oct-bookmark_slash_fill"] = 0xf493, + ["oct-briefcase"] = 0xf491, + ["oct-broadcast"] = 0xf43c, + ["oct-browser"] = 0xf488, + ["oct-bug"] = 0xf46f, + ["oct-cache"] = 0xf49b, + ["oct-calendar"] = 0xf455, + ["oct-check"] = 0xf42e, + ["oct-check_circle"] = 0xf49e, + ["oct-check_circle_fill"] = 0xf4a4, + ["oct-checkbox"] = 0xf4a7, + ["oct-checklist"] = 0xf45e, + ["oct-chevron_down"] = 0xf47c, + ["oct-chevron_left"] = 0xf47d, + ["oct-chevron_right"] = 0xf460, + ["oct-chevron_up"] = 0xf47b, + ["oct-circle"] = 0xf4aa, + ["oct-circle_slash"] = 0xf468, + ["oct-clock"] = 0xf43a, + ["oct-clock_fill"] = 0xf4ab, + ["oct-cloud"] = 0xf4ac, + ["oct-cloud_offline"] = 0xf4ad, + ["oct-code"] = 0xf44f, + ["oct-code_of_conduct"] = 0xf4ae, + ["oct-code_review"] = 0xf4af, + ["oct-code_square"] = 0xf4b0, + ["oct-codescan"] = 0xf4b1, + ["oct-codescan_checkmark"] = 0xf4b2, + ["oct-codespaces"] = 0xf4b3, + ["oct-columns"] = 0xf4b4, + ["oct-command_palette"] = 0xf4b5, + ["oct-comment"] = 0xf41f, + ["oct-comment_discussion"] = 0xf442, + ["oct-commit"] = 0xf4b6, + ["oct-container"] = 0xf4b7, + ["oct-copilot"] = 0xf4b8, + ["oct-copilot_error"] = 0xf4b9, + ["oct-copilot_warning"] = 0xf4ba, + ["oct-copy"] = 0xf4bb, + ["oct-cpu"] = 0xf4bc, + ["oct-credit_card"] = 0xf439, + ["oct-cross_reference"] = 0xf4bd, + ["oct-dash"] = 0xf48b, + ["oct-database"] = 0xf472, + ["oct-dependabot"] = 0xf4be, + ["oct-desktop_download"] = 0xf498, + ["oct-device_camera"] = 0xf446, + ["oct-device_camera_video"] = 0xf447, + ["oct-device_desktop"] = 0xf4a9, + ["oct-device_mobile"] = 0xf42c, + ["oct-diamond"] = 0xf4bf, + ["oct-diff"] = 0xf440, + ["oct-diff_added"] = 0xf457, + ["oct-diff_ignored"] = 0xf474, + ["oct-diff_modified"] = 0xf459, + ["oct-diff_removed"] = 0xf458, + ["oct-diff_renamed"] = 0xf45a, + ["oct-discussion_closed"] = 0xf4c0, + ["oct-discussion_duplicate"] = 0xf4c1, + ["oct-discussion_outdated"] = 0xf4c2, + ["oct-dot"] = 0xf4c3, + ["oct-dot_fill"] = 0xf444, + ["oct-download"] = 0xf409, + ["oct-duplicate"] = 0xf4c4, + ["oct-ellipsis"] = 0xf475, + ["oct-eye"] = 0xf441, + ["oct-eye_closed"] = 0xf4c5, + ["oct-feed_discussion"] = 0xf4c6, + ["oct-feed_forked"] = 0xf4c7, + ["oct-feed_heart"] = 0xf4c8, + ["oct-feed_merged"] = 0xf4c9, + ["oct-feed_person"] = 0xf4ca, + ["oct-feed_repo"] = 0xf4cb, + ["oct-feed_rocket"] = 0xf4cc, + ["oct-feed_star"] = 0xf4cd, + ["oct-feed_tag"] = 0xf4ce, + ["oct-feed_trophy"] = 0xf4cf, + ["oct-file"] = 0xf4a5, + ["oct-file_added"] = 0xf4d0, + ["oct-file_badge"] = 0xf4d1, + ["oct-file_binary"] = 0xf471, + ["oct-file_code"] = 0xf40d, + ["oct-file_diff"] = 0xf4d2, + ["oct-file_directory"] = 0xf413, + ["oct-file_directory_fill"] = 0xf4d3, + ["oct-file_directory_open_fill"] = 0xf4d4, + ["oct-file_media"] = 0xf40f, + ["oct-file_moved"] = 0xf4d5, + ["oct-file_removed"] = 0xf4d6, + ["oct-file_submodule"] = 0xf414, + ["oct-file_symlink_directory"] = 0xf482, + ["oct-file_symlink_file"] = 0xf481, + ["oct-file_zip"] = 0xf410, + ["oct-filter"] = 0xf4d7, + ["oct-fiscal_host"] = 0xf4d8, + ["oct-flame"] = 0xf490, + ["oct-fold"] = 0xf48c, + ["oct-fold_down"] = 0xf4d9, + ["oct-fold_up"] = 0xf4da, + ["oct-gear"] = 0xf423, + ["oct-gift"] = 0xf436, + ["oct-git_branch"] = 0xf418, + ["oct-git_commit"] = 0xf417, + ["oct-git_compare"] = 0xf47f, + ["oct-git_merge"] = 0xf419, + ["oct-git_merge_queue"] = 0xf4db, + ["oct-git_pull_request"] = 0xf407, + ["oct-git_pull_request_closed"] = 0xf4dc, + ["oct-git_pull_request_draft"] = 0xf4dd, + ["oct-globe"] = 0xf484, + ["oct-goal"] = 0xf4de, + ["oct-grabber"] = 0xf4a6, + ["oct-graph"] = 0xf437, + ["oct-hash"] = 0xf4df, + ["oct-heading"] = 0xf4e0, + ["oct-heart"] = 0x2665, + ["oct-heart_fill"] = 0xf4e1, + ["oct-history"] = 0xf464, + ["oct-home"] = 0xf46d, + ["oct-home_fill"] = 0xf4e2, + ["oct-horizontal_rule"] = 0xf45b, + ["oct-hourglass"] = 0xf4e3, + ["oct-hubot"] = 0xf477, + ["oct-id_badge"] = 0xf4e4, + ["oct-image"] = 0xf4e5, + ["oct-inbox"] = 0xf48d, + ["oct-infinity"] = 0xf4e6, + ["oct-info"] = 0xf449, + ["oct-issue_closed"] = 0xf41d, + ["oct-issue_draft"] = 0xf4e7, + ["oct-issue_opened"] = 0xf41b, + ["oct-issue_reopened"] = 0xf41c, + ["oct-issue_tracked_by"] = 0xf4e8, + ["oct-issue_tracks"] = 0xf4e9, + ["oct-italic"] = 0xf49f, + ["oct-iterations"] = 0xf4ea, + ["oct-kebab_horizontal"] = 0xf4eb, + ["oct-key"] = 0xf43d, + ["oct-key_asterisk"] = 0xf4ec, + ["oct-law"] = 0xf495, + ["oct-light_bulb"] = 0xf400, + ["oct-link"] = 0xf44c, + ["oct-link_external"] = 0xf465, + ["oct-list_ordered"] = 0xf452, + ["oct-list_unordered"] = 0xf451, + ["oct-location"] = 0xf450, + ["oct-lock"] = 0xf456, + ["oct-log"] = 0xf4ed, + ["oct-logo_gist"] = 0xf480, + ["oct-logo_github"] = 0xf470, + ["oct-mail"] = 0xf42f, + ["oct-mark_github"] = 0xf408, + ["oct-markdown"] = 0xf48a, + ["oct-megaphone"] = 0xf45f, + ["oct-mention"] = 0xf486, + ["oct-meter"] = 0xf463, + ["oct-milestone"] = 0xf45d, + ["oct-mirror"] = 0xf41a, + ["oct-moon"] = 0xf4ee, + ["oct-mortar_board"] = 0xf494, + ["oct-move_to_bottom"] = 0xf4ef, + ["oct-move_to_end"] = 0xf4f0, + ["oct-move_to_start"] = 0xf4f1, + ["oct-move_to_top"] = 0xf4f2, + ["oct-multi_select"] = 0xf4f3, + ["oct-mute"] = 0xf466, + ["oct-no_entry"] = 0xf4f4, + ["oct-north_star"] = 0xf4f5, + ["oct-note"] = 0xf4f6, + ["oct-number"] = 0xf4f7, + ["oct-organization"] = 0xf42b, + ["oct-package"] = 0xf487, + ["oct-package_dependencies"] = 0xf4f8, + ["oct-package_dependents"] = 0xf4f9, + ["oct-paintbrush"] = 0xf48f, + ["oct-paper_airplane"] = 0xf4fa, + ["oct-paperclip"] = 0xf4fb, + ["oct-passkey_fill"] = 0xf4fc, + ["oct-paste"] = 0xf429, + ["oct-pencil"] = 0xf448, + ["oct-people"] = 0xf4fd, + ["oct-person"] = 0xf415, + ["oct-person_add"] = 0xf4fe, + ["oct-person_fill"] = 0xf4ff, + ["oct-pin"] = 0xf435, + ["oct-play"] = 0xf500, + ["oct-plug"] = 0xf492, + ["oct-plus"] = 0xf44d, + ["oct-plus_circle"] = 0xf501, + ["oct-project"] = 0xf502, + ["oct-project_roadmap"] = 0xf503, + ["oct-project_symlink"] = 0xf504, + ["oct-project_template"] = 0xf505, + ["oct-pulse"] = 0xf469, + ["oct-question"] = 0xf420, + ["oct-quote"] = 0xf453, + ["oct-read"] = 0xf430, + ["oct-rel_file_path"] = 0xf506, + ["oct-reply"] = 0xf4a8, + ["oct-repo"] = 0xf401, + ["oct-repo_clone"] = 0xf43f, + ["oct-repo_deleted"] = 0xf507, + ["oct-repo_forked"] = 0xf402, + ["oct-repo_locked"] = 0xf508, + ["oct-repo_pull"] = 0xf404, + ["oct-repo_push"] = 0xf403, + ["oct-repo_template"] = 0xf509, + ["oct-report"] = 0xf50a, + ["oct-rocket"] = 0xf427, + ["oct-rows"] = 0xf50b, + ["oct-rss"] = 0xf428, + ["oct-ruby"] = 0xf43b, + ["oct-screen_full"] = 0xf50c, + ["oct-screen_normal"] = 0xf50d, + ["oct-search"] = 0xf422, + ["oct-server"] = 0xf473, + ["oct-share"] = 0xf50e, + ["oct-share_android"] = 0xf50f, + ["oct-shield"] = 0xf49c, + ["oct-shield_check"] = 0xf510, + ["oct-shield_lock"] = 0xf511, + ["oct-shield_slash"] = 0xf512, + ["oct-shield_x"] = 0xf513, + ["oct-sidebar_collapse"] = 0xf514, + ["oct-sidebar_expand"] = 0xf515, + ["oct-sign_in"] = 0xf42a, + ["oct-sign_out"] = 0xf426, + ["oct-single_select"] = 0xf516, + ["oct-skip"] = 0xf517, + ["oct-skip_fill"] = 0xf518, + ["oct-sliders"] = 0xf462, + ["oct-smiley"] = 0xf4a2, + ["oct-sort_asc"] = 0xf519, + ["oct-sort_desc"] = 0xf51a, + ["oct-sparkle_fill"] = 0xf51b, + ["oct-sponsor_tiers"] = 0xf51c, + ["oct-square"] = 0xf51d, + ["oct-square_fill"] = 0xf445, + ["oct-squirrel"] = 0xf483, + ["oct-stack"] = 0xf51e, + ["oct-star"] = 0xf41e, + ["oct-star_fill"] = 0xf51f, + ["oct-stop"] = 0xf46e, + ["oct-stopwatch"] = 0xf520, + ["oct-strikethrough"] = 0xf521, + ["oct-sun"] = 0xf522, + ["oct-sync"] = 0xf46a, + ["oct-tab"] = 0xf523, + ["oct-tab_external"] = 0xf524, + ["oct-table"] = 0xf525, + ["oct-tag"] = 0xf412, + ["oct-tasklist"] = 0xf4a0, + ["oct-telescope"] = 0xf46b, + ["oct-telescope_fill"] = 0xf526, + ["oct-terminal"] = 0xf489, + ["oct-three_bars"] = 0xf44e, + ["oct-thumbsdown"] = 0xf497, + ["oct-thumbsup"] = 0xf496, + ["oct-tools"] = 0xf425, + ["oct-trash"] = 0xf48e, + ["oct-triangle_down"] = 0xf44b, + ["oct-triangle_left"] = 0xf438, + ["oct-triangle_right"] = 0xf44a, + ["oct-triangle_up"] = 0xf47e, + ["oct-trophy"] = 0xf527, + ["oct-typography"] = 0xf528, + ["oct-unfold"] = 0xf42d, + ["oct-unlink"] = 0xf529, + ["oct-unlock"] = 0xf52a, + ["oct-unmute"] = 0xf485, + ["oct-unread"] = 0xf52b, + ["oct-unverified"] = 0xf4a3, + ["oct-upload"] = 0xf40a, + ["oct-verified"] = 0xf4a1, + ["oct-versions"] = 0xf454, + ["oct-video"] = 0xf52c, + ["oct-webhook"] = 0xf52d, + ["oct-workflow"] = 0xf52e, + ["oct-x"] = 0xf467, + ["oct-x_circle"] = 0xf52f, + ["oct-x_circle_fill"] = 0xf530, + ["oct-zap"] = 0x26a1, + ["oct-zoom_in"] = 0xf531, + ["oct-zoom_out"] = 0xf532, + ["pl-branch"] = 0xe0a0, + ["pl-current_line"] = 0xe0a1, + ["pl-hostname"] = 0xe0a2, + ["pl-left_hard_divider"] = 0xe0b0, + ["pl-left_soft_divider"] = 0xe0b1, + ["pl-line_number"] = 0xe0a1, + ["pl-readonly"] = 0xe0a2, + ["pl-right_hard_divider"] = 0xe0b2, + ["pl-right_soft_divider"] = 0xe0b3, + ["ple-backslash_separator"] = 0xe0b9, + ["ple-backslash_separator_redundant"] = 0xe0bf, + ["ple-column_number"] = 0xe0a3, + ["ple-current_column"] = 0xe0a3, + ["ple-flame_thick"] = 0xe0c0, + ["ple-flame_thick_mirrored"] = 0xe0c2, + ["ple-flame_thin"] = 0xe0c1, + ["ple-flame_thin_mirrored"] = 0xe0c3, + ["ple-forwardslash_separator"] = 0xe0bb, + ["ple-forwardslash_separator_redundant"] = 0xe0bd, + ["ple-honeycomb"] = 0xe0cc, + ["ple-honeycomb_outline"] = 0xe0cd, + ["ple-ice_waveform"] = 0xe0c8, + ["ple-ice_waveform_mirrored"] = 0xe0ca, + ["ple-left_half_circle_thick"] = 0xe0b6, + ["ple-left_half_circle_thin"] = 0xe0b7, + ["ple-lego_block_facing"] = 0xe0d0, + ["ple-lego_block_sideways"] = 0xe0d1, + ["ple-lego_separator"] = 0xe0ce, + ["ple-lego_separator_thin"] = 0xe0cf, + ["ple-lower_left_triangle"] = 0xe0b8, + ["ple-lower_right_triangle"] = 0xe0ba, + ["ple-pixelated_squares_big"] = 0xe0c6, + ["ple-pixelated_squares_big_mirrored"] = 0xe0c7, + ["ple-pixelated_squares_small"] = 0xe0c4, + ["ple-pixelated_squares_small_mirrored"] = 0xe0c5, + ["ple-right_half_circle_thick"] = 0xe0b4, + ["ple-right_half_circle_thin"] = 0xe0b5, + ["ple-trapezoid_top_bottom"] = 0xe0d2, + ["ple-trapezoid_top_bottom_mirrored"] = 0xe0d4, + ["ple-upper_left_triangle"] = 0xe0bc, + ["ple-upper_right_triangle"] = 0xe0be, + ["pom-away"] = 0xe007, + ["pom-clean_code"] = 0xe000, + ["pom-external_interruption"] = 0xe00a, + ["pom-internal_interruption"] = 0xe009, + ["pom-long_pause"] = 0xe006, + ["pom-pair_programming"] = 0xe008, + ["pom-pomodoro_done"] = 0xe001, + ["pom-pomodoro_estimated"] = 0xe002, + ["pom-pomodoro_squashed"] = 0xe004, + ["pom-pomodoro_ticking"] = 0xe003, + ["pom-short_pause"] = 0xe005, + ["seti-apple"] = 0xe635, + ["seti-argdown"] = 0xe636, + ["seti-asm"] = 0xe637, + ["seti-audio"] = 0xe638, + ["seti-babel"] = 0xe639, + ["seti-bazel"] = 0xe63a, + ["seti-bicep"] = 0xe63b, + ["seti-bower"] = 0xe61a, + ["seti-bsl"] = 0xe63c, + ["seti-c"] = 0xe649, + ["seti-c_sharp"] = 0xe648, + ["seti-cake"] = 0xe63e, + ["seti-cake_php"] = 0xe63d, + ["seti-checkbox"] = 0xe63f, + ["seti-checkbox_unchecked"] = 0xe640, + ["seti-cjsx"] = 0xe61b, + ["seti-clock"] = 0xe641, + ["seti-clojure"] = 0xe642, + ["seti-code_climate"] = 0xe643, + ["seti-code_search"] = 0xe644, + ["seti-coffee"] = 0xe61b, + ["seti-coldfusion"] = 0xe645, + ["seti-config"] = 0xe615, + ["seti-cpp"] = 0xe646, + ["seti-crystal"] = 0xe62f, + ["seti-crystal_embedded"] = 0xe647, + ["seti-css"] = 0xe614, + ["seti-csv"] = 0xe64a, + ["seti-cu"] = 0xe64b, + ["seti-d"] = 0xe651, + ["seti-dart"] = 0xe64c, + ["seti-db"] = 0xe64d, + ["seti-default"] = 0xe64e, + ["seti-deprecation_cop"] = 0xe64f, + ["seti-docker"] = 0xe650, + ["seti-editorconfig"] = 0xe652, + ["seti-ejs"] = 0xe618, + ["seti-elixir"] = 0xe62d, + ["seti-elixir_script"] = 0xe653, + ["seti-elm"] = 0xe62c, + ["seti-error"] = 0xe654, + ["seti-eslint"] = 0xe655, + ["seti-ethereum"] = 0xe656, + ["seti-f_sharp"] = 0xe65a, + ["seti-favicon"] = 0xe623, + ["seti-firebase"] = 0xe657, + ["seti-firefox"] = 0xe658, + ["seti-folder"] = 0xe613, + ["seti-font"] = 0xe659, + ["seti-git"] = 0xe65d, + ["seti-git_folder"] = 0xe65d, + ["seti-git_ignore"] = 0xe65d, + ["seti-github"] = 0xe65b, + ["seti-gitlab"] = 0xe65c, + ["seti-go"] = 0xe627, + ["seti-go2"] = 0xe65e, + ["seti-godot"] = 0xe65f, + ["seti-gradle"] = 0xe660, + ["seti-grails"] = 0xe661, + ["seti-graphql"] = 0xe662, + ["seti-grunt"] = 0xe611, + ["seti-gulp"] = 0xe610, + ["seti-hacklang"] = 0xe663, + ["seti-haml"] = 0xe664, + ["seti-happenings"] = 0xe665, + ["seti-haskell"] = 0xe61f, + ["seti-haxe"] = 0xe666, + ["seti-heroku"] = 0xe607, + ["seti-hex"] = 0xe667, + ["seti-home"] = 0xe617, + ["seti-html"] = 0xe60e, + ["seti-ignored"] = 0xe668, + ["seti-illustrator"] = 0xe669, + ["seti-image"] = 0xe60d, + ["seti-info"] = 0xe66a, + ["seti-ionic"] = 0xe66b, + ["seti-jade"] = 0xe66c, + ["seti-java"] = 0xe66d, + ["seti-javascript"] = 0xe60c, + ["seti-jenkins"] = 0xe66e, + ["seti-jinja"] = 0xe66f, + ["seti-json"] = 0xe60b, + ["seti-julia"] = 0xe624, + ["seti-karma"] = 0xe622, + ["seti-kotlin"] = 0xe634, + ["seti-less"] = 0xe60b, + ["seti-license"] = 0xe60a, + ["seti-liquid"] = 0xe670, + ["seti-livescript"] = 0xe671, + ["seti-lock"] = 0xe672, + ["seti-lua"] = 0xe620, + ["seti-makefile"] = 0xe673, + ["seti-markdown"] = 0xe609, + ["seti-maven"] = 0xe674, + ["seti-mdo"] = 0xe675, + ["seti-mustache"] = 0xe60f, + ["seti-new_file"] = 0xe676, + ["seti-nim"] = 0xe677, + ["seti-notebook"] = 0xe678, + ["seti-npm"] = 0xe616, + ["seti-npm_ignored"] = 0xe616, + ["seti-nunjucks"] = 0xe679, + ["seti-ocaml"] = 0xe67a, + ["seti-odata"] = 0xe67b, + ["seti-pddl"] = 0xe67c, + ["seti-pdf"] = 0xe67d, + ["seti-perl"] = 0xe67e, + ["seti-photoshop"] = 0xe67f, + ["seti-php"] = 0xe608, + ["seti-pipeline"] = 0xe680, + ["seti-plan"] = 0xe681, + ["seti-platformio"] = 0xe682, + ["seti-play_arrow"] = 0xe602, + ["seti-powershell"] = 0xe683, + ["seti-prisma"] = 0xe684, + ["seti-project"] = 0xe601, + ["seti-prolog"] = 0xe685, + ["seti-pug"] = 0xe686, + ["seti-puppet"] = 0xe631, + ["seti-purescript"] = 0xe630, + ["seti-python"] = 0xe606, + ["seti-r"] = 0xe68a, + ["seti-rails"] = 0xe604, + ["seti-react"] = 0xe625, + ["seti-reasonml"] = 0xe687, + ["seti-rescript"] = 0xe688, + ["seti-rollup"] = 0xe689, + ["seti-ruby"] = 0xe605, + ["seti-rust"] = 0xe68b, + ["seti-salesforce"] = 0xe68c, + ["seti-sass"] = 0xe603, + ["seti-sbt"] = 0xe68d, + ["seti-scala"] = 0xe68e, + ["seti-search"] = 0xe68f, + ["seti-settings"] = 0xe690, + ["seti-shell"] = 0xe691, + ["seti-slim"] = 0xe692, + ["seti-smarty"] = 0xe693, + ["seti-spring"] = 0xe694, + ["seti-stylelint"] = 0xe695, + ["seti-stylus"] = 0xe600, + ["seti-sublime"] = 0xe696, + ["seti-svelte"] = 0xe697, + ["seti-svg"] = 0xe698, + ["seti-swift"] = 0xe699, + ["seti-terraform"] = 0xe69a, + ["seti-tex"] = 0xe69b, + ["seti-text"] = 0xe612, + ["seti-time_cop"] = 0xe641, + ["seti-todo"] = 0xe69c, + ["seti-tsconfig"] = 0xe69d, + ["seti-twig"] = 0xe61c, + ["seti-typescript"] = 0xe628, + ["seti-vala"] = 0xe69e, + ["seti-video"] = 0xe69f, + ["seti-vue"] = 0xe6a0, + ["seti-wasm"] = 0xe6a1, + ["seti-wat"] = 0xe6a2, + ["seti-webpack"] = 0xe6a3, + ["seti-wgt"] = 0xe6a4, + ["seti-word"] = 0xe6a5, + ["seti-xls"] = 0xe6a6, + ["seti-xml"] = 0xe619, + ["seti-yarn"] = 0xe6a7, + ["seti-yml"] = 0xe6a8, + ["seti-zig"] = 0xe6a9, + ["seti-zip"] = 0xe6aa, + ["weather-alien"] = 0xe36e, + ["weather-aliens"] = 0xe345, + ["weather-barometer"] = 0xe372, + ["weather-celsius"] = 0xe339, + ["weather-cloud"] = 0xe33d, + ["weather-cloud_down"] = 0xe33a, + ["weather-cloud_refresh"] = 0xe33b, + ["weather-cloud_up"] = 0xe33c, + ["weather-cloudy"] = 0xe312, + ["weather-cloudy_gusts"] = 0xe310, + ["weather-cloudy_windy"] = 0xe311, + ["weather-day_cloudy"] = 0xe302, + ["weather-day_cloudy_gusts"] = 0xe300, + ["weather-day_cloudy_high"] = 0xe376, + ["weather-day_cloudy_windy"] = 0xe301, + ["weather-day_fog"] = 0xe303, + ["weather-day_hail"] = 0xe304, + ["weather-day_haze"] = 0xe3ae, + ["weather-day_light_wind"] = 0xe3bc, + ["weather-day_lightning"] = 0xe305, + ["weather-day_rain"] = 0xe308, + ["weather-day_rain_mix"] = 0xe306, + ["weather-day_rain_wind"] = 0xe307, + ["weather-day_showers"] = 0xe309, + ["weather-day_sleet"] = 0xe3aa, + ["weather-day_sleet_storm"] = 0xe362, + ["weather-day_snow"] = 0xe30a, + ["weather-day_snow_thunderstorm"] = 0xe365, + ["weather-day_snow_wind"] = 0xe35f, + ["weather-day_sprinkle"] = 0xe30b, + ["weather-day_storm_showers"] = 0xe30e, + ["weather-day_sunny"] = 0xe30d, + ["weather-day_sunny_overcast"] = 0xe30c, + ["weather-day_thunderstorm"] = 0xe30f, + ["weather-day_windy"] = 0xe37d, + ["weather-degrees"] = 0xe33e, + ["weather-direction_down"] = 0xe340, + ["weather-direction_down_left"] = 0xe33f, + ["weather-direction_down_right"] = 0xe380, + ["weather-direction_left"] = 0xe344, + ["weather-direction_right"] = 0xe349, + ["weather-direction_up"] = 0xe353, + ["weather-direction_up_left"] = 0xe37f, + ["weather-direction_up_right"] = 0xe352, + ["weather-dust"] = 0xe35d, + ["weather-earthquake"] = 0xe3be, + ["weather-fahrenheit"] = 0xe341, + ["weather-fire"] = 0xe3bf, + ["weather-flood"] = 0xe375, + ["weather-fog"] = 0xe313, + ["weather-gale_warning"] = 0xe3c5, + ["weather-hail"] = 0xe314, + ["weather-horizon"] = 0xe343, + ["weather-horizon_alt"] = 0xe342, + ["weather-hot"] = 0xe36b, + ["weather-humidity"] = 0xe373, + ["weather-hurricane"] = 0xe36c, + ["weather-hurricane_warning"] = 0xe3c7, + ["weather-lightning"] = 0xe315, + ["weather-lunar_eclipse"] = 0xe369, + ["weather-meteor"] = 0xe36a, + ["weather-moon_alt_first_quarter"] = 0xe3ce, + ["weather-moon_alt_full"] = 0xe3d5, + ["weather-moon_alt_new"] = 0xe3e3, + ["weather-moon_alt_third_quarter"] = 0xe3dc, + ["weather-moon_alt_waning_crescent_1"] = 0xe3dd, + ["weather-moon_alt_waning_crescent_2"] = 0xe3de, + ["weather-moon_alt_waning_crescent_3"] = 0xe3df, + ["weather-moon_alt_waning_crescent_4"] = 0xe3e0, + ["weather-moon_alt_waning_crescent_5"] = 0xe3e1, + ["weather-moon_alt_waning_crescent_6"] = 0xe3e2, + ["weather-moon_alt_waning_gibbous_1"] = 0xe3d6, + ["weather-moon_alt_waning_gibbous_2"] = 0xe3d7, + ["weather-moon_alt_waning_gibbous_3"] = 0xe3d8, + ["weather-moon_alt_waning_gibbous_4"] = 0xe3d9, + ["weather-moon_alt_waning_gibbous_5"] = 0xe3da, + ["weather-moon_alt_waning_gibbous_6"] = 0xe3db, + ["weather-moon_alt_waxing_crescent_1"] = 0xe3c8, + ["weather-moon_alt_waxing_crescent_2"] = 0xe3c9, + ["weather-moon_alt_waxing_crescent_3"] = 0xe3ca, + ["weather-moon_alt_waxing_crescent_4"] = 0xe3cb, + ["weather-moon_alt_waxing_crescent_5"] = 0xe3cc, + ["weather-moon_alt_waxing_crescent_6"] = 0xe3cd, + ["weather-moon_alt_waxing_gibbous_1"] = 0xe3cf, + ["weather-moon_alt_waxing_gibbous_2"] = 0xe3d0, + ["weather-moon_alt_waxing_gibbous_3"] = 0xe3d1, + ["weather-moon_alt_waxing_gibbous_4"] = 0xe3d2, + ["weather-moon_alt_waxing_gibbous_5"] = 0xe3d3, + ["weather-moon_alt_waxing_gibbous_6"] = 0xe3d4, + ["weather-moon_first_quarter"] = 0xe394, + ["weather-moon_full"] = 0xe39b, + ["weather-moon_new"] = 0xe38d, + ["weather-moon_third_quarter"] = 0xe3a2, + ["weather-moon_waning_crescent_1"] = 0xe3a3, + ["weather-moon_waning_crescent_2"] = 0xe3a4, + ["weather-moon_waning_crescent_3"] = 0xe3a5, + ["weather-moon_waning_crescent_4"] = 0xe3a6, + ["weather-moon_waning_crescent_5"] = 0xe3a7, + ["weather-moon_waning_crescent_6"] = 0xe3a8, + ["weather-moon_waning_gibbous_1"] = 0xe39c, + ["weather-moon_waning_gibbous_2"] = 0xe39d, + ["weather-moon_waning_gibbous_3"] = 0xe39e, + ["weather-moon_waning_gibbous_4"] = 0xe39f, + ["weather-moon_waning_gibbous_5"] = 0xe3a0, + ["weather-moon_waning_gibbous_6"] = 0xe3a1, + ["weather-moon_waxing_crescent_1"] = 0xe38e, + ["weather-moon_waxing_crescent_2"] = 0xe38f, + ["weather-moon_waxing_crescent_3"] = 0xe390, + ["weather-moon_waxing_crescent_4"] = 0xe391, + ["weather-moon_waxing_crescent_5"] = 0xe392, + ["weather-moon_waxing_crescent_6"] = 0xe393, + ["weather-moon_waxing_gibbous_1"] = 0xe395, + ["weather-moon_waxing_gibbous_2"] = 0xe396, + ["weather-moon_waxing_gibbous_3"] = 0xe397, + ["weather-moon_waxing_gibbous_4"] = 0xe398, + ["weather-moon_waxing_gibbous_5"] = 0xe399, + ["weather-moon_waxing_gibbous_6"] = 0xe39a, + ["weather-moonrise"] = 0xe3c1, + ["weather-moonset"] = 0xe3c2, + ["weather-na"] = 0xe374, + ["weather-night_alt_cloudy"] = 0xe37e, + ["weather-night_alt_cloudy_gusts"] = 0xe31f, + ["weather-night_alt_cloudy_high"] = 0xe377, + ["weather-night_alt_cloudy_windy"] = 0xe320, + ["weather-night_alt_hail"] = 0xe321, + ["weather-night_alt_lightning"] = 0xe322, + ["weather-night_alt_partly_cloudy"] = 0xe379, + ["weather-night_alt_rain"] = 0xe325, + ["weather-night_alt_rain_mix"] = 0xe323, + ["weather-night_alt_rain_wind"] = 0xe324, + ["weather-night_alt_showers"] = 0xe326, + ["weather-night_alt_sleet"] = 0xe3ac, + ["weather-night_alt_sleet_storm"] = 0xe364, + ["weather-night_alt_snow"] = 0xe327, + ["weather-night_alt_snow_thunderstorm"] = 0xe367, + ["weather-night_alt_snow_wind"] = 0xe361, + ["weather-night_alt_sprinkle"] = 0xe328, + ["weather-night_alt_storm_showers"] = 0xe329, + ["weather-night_alt_thunderstorm"] = 0xe32a, + ["weather-night_clear"] = 0xe32b, + ["weather-night_cloudy"] = 0xe32e, + ["weather-night_cloudy_gusts"] = 0xe32c, + ["weather-night_cloudy_high"] = 0xe378, + ["weather-night_cloudy_windy"] = 0xe32d, + ["weather-night_fog"] = 0xe346, + ["weather-night_hail"] = 0xe32f, + ["weather-night_lightning"] = 0xe330, + ["weather-night_partly_cloudy"] = 0xe37b, + ["weather-night_rain"] = 0xe333, + ["weather-night_rain_mix"] = 0xe331, + ["weather-night_rain_wind"] = 0xe332, + ["weather-night_showers"] = 0xe334, + ["weather-night_sleet"] = 0xe3ab, + ["weather-night_sleet_storm"] = 0xe363, + ["weather-night_snow"] = 0xe335, + ["weather-night_snow_thunderstorm"] = 0xe366, + ["weather-night_snow_wind"] = 0xe360, + ["weather-night_sprinkle"] = 0xe336, + ["weather-night_storm_showers"] = 0xe337, + ["weather-night_thunderstorm"] = 0xe338, + ["weather-rain"] = 0xe318, + ["weather-rain_mix"] = 0xe316, + ["weather-rain_wind"] = 0xe317, + ["weather-raindrop"] = 0xe371, + ["weather-raindrops"] = 0xe34a, + ["weather-refresh"] = 0xe348, + ["weather-refresh_alt"] = 0xe347, + ["weather-sandstorm"] = 0xe37a, + ["weather-showers"] = 0xe319, + ["weather-sleet"] = 0xe3ad, + ["weather-small_craft_advisory"] = 0xe3c4, + ["weather-smog"] = 0xe36d, + ["weather-smoke"] = 0xe35c, + ["weather-snow"] = 0xe31a, + ["weather-snow_wind"] = 0xe35e, + ["weather-snowflake_cold"] = 0xe36f, + ["weather-solar_eclipse"] = 0xe368, + ["weather-sprinkle"] = 0xe31b, + ["weather-stars"] = 0xe370, + ["weather-storm_showers"] = 0xe31c, + ["weather-storm_warning"] = 0xe3c6, + ["weather-strong_wind"] = 0xe34b, + ["weather-sunrise"] = 0xe34c, + ["weather-sunset"] = 0xe34d, + ["weather-thermometer"] = 0xe350, + ["weather-thermometer_exterior"] = 0xe34e, + ["weather-thermometer_internal"] = 0xe34f, + ["weather-thunderstorm"] = 0xe31d, + ["weather-time_1"] = 0xe382, + ["weather-time_10"] = 0xe38b, + ["weather-time_11"] = 0xe38c, + ["weather-time_12"] = 0xe381, + ["weather-time_2"] = 0xe383, + ["weather-time_3"] = 0xe384, + ["weather-time_4"] = 0xe385, + ["weather-time_5"] = 0xe386, + ["weather-time_6"] = 0xe387, + ["weather-time_7"] = 0xe388, + ["weather-time_8"] = 0xe389, + ["weather-time_9"] = 0xe38a, + ["weather-tornado"] = 0xe351, + ["weather-train"] = 0xe3c3, + ["weather-tsunami"] = 0xe3bd, + ["weather-umbrella"] = 0xe37c, + ["weather-volcano"] = 0xe3c0, + ["weather-wind_beaufort_0"] = 0xe3af, + ["weather-wind_beaufort_1"] = 0xe3b0, + ["weather-wind_beaufort_10"] = 0xe3b9, + ["weather-wind_beaufort_11"] = 0xe3ba, + ["weather-wind_beaufort_12"] = 0xe3bb, + ["weather-wind_beaufort_2"] = 0xe3b1, + ["weather-wind_beaufort_3"] = 0xe3b2, + ["weather-wind_beaufort_4"] = 0xe3b3, + ["weather-wind_beaufort_5"] = 0xe3b4, + ["weather-wind_beaufort_6"] = 0xe3b5, + ["weather-wind_beaufort_7"] = 0xe3b6, + ["weather-wind_beaufort_8"] = 0xe3b7, + ["weather-wind_beaufort_9"] = 0xe3b8, + ["weather-wind_direction"] = 0xe3a9, + ["weather-wind_east"] = 0xe35b, + ["weather-wind_north"] = 0xe35a, + ["weather-wind_north_east"] = 0xe359, + ["weather-wind_north_west"] = 0xe358, + ["weather-wind_south"] = 0xe357, + ["weather-wind_south_east"] = 0xe356, + ["weather-wind_south_west"] = 0xe355, + ["weather-wind_west"] = 0xe354, + ["weather-windy"] = 0xe31e, +} + +local utf8 = setmetatable({}, { + __index = function(t, k) + local cp = codepoints[k] + if not cp then return nil end + + local res + if cp < 0x0080 then + res = cp + elseif cp < 0x0800 then + res = string.char(0xC0 | (cp >> 6), 0x80 | (cp & 0x3F)) + elseif cp < 0x10000 then + res = string.char(0xE0 | (cp >> 12), 0x80 | ((cp >> 6) & 0x3F), 0x80 | (cp & 0x3F)) + else + res = string.char(0xF0 | (cp >> 18), 0x80 | ((cp >> 12) & 0x3F), 0x80 | ((cp >> 6) & 0x3F), 0x80 | (cp & 0x3F)) + end + + t[k] = res + return res + end +}) + +return { + codepoints = codepoints, + utf8 = utf8, + path = DATADIR .. PATHSEP .. "libraries" .. PATHSEP .. "font_symbols_nerdfont_mono_regular" .. PATHSEP .. "SymbolsNerdFontMono-Regular.ttf" +} diff --git a/debian/extra/libraries/widget/button.lua b/debian/extra/libraries/widget/button.lua new file mode 100644 index 0000000..f346d31 --- /dev/null +++ b/debian/extra/libraries/widget/button.lua @@ -0,0 +1,163 @@ +-- +-- Button Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local style = require "core.style" +local Widget = require "libraries.widget" + +---@class widget.button.icon +---@field public code string | nil +---@field public color renderer.color | nil +---@field public hover_color renderer.color | nil +local ButtonIcon = {} + +---@class widget.button : widget +---@overload fun(parent:widget?, label:string?):widget.button +---@field public padding widget.position +---@field public icon widget.button.icon +---@field public expanded boolean +local Button = Widget:extend() + +---Constructor +---@param parent widget +---@param label? string +function Button:new(parent, label) + Button.super.new(self, parent) + + self.type_name = "widget.button" + + self.icon = { + code = nil, color = nil, hover_color = nil + } + + self.padding = { + x = style.padding.x, + y = style.padding.y + } + + self.expanded = false + + self:set_label(label or "") +end + +---When set to true the button width will be the same as parent +---@param expand? boolean | nil +function Button:toggle_expand(expand) + if type(expand) == "boolean" then + self.expanded = expand + else + self.expanded = not self.expanded + end +end + +---Set the icon drawn alongside the button text. +---@param code? string +---@param color? renderer.color +---@param hover_color? renderer.color +function Button:set_icon(code, color, hover_color) + self.icon.code = code + self.icon.color = color + self.icon.hover_color = hover_color + + self:set_label(self.label) +end + +---Set the button text and recalculates the widget size. +---@param text string +function Button:set_label(text) + Button.super.set_label(self, text) + + local font = self:get_font() + local border = self.border.width * 2 + + if self.expanded and self.parent then + self.size.x = self.parent.size.x - self.position.rx - border + else + self.size.x = font:get_width(self.label) + (self.padding.x * 2) - border + end + + self.size.y = font:get_height() + (self.padding.y * 2) - border + + if self.icon.code then + local icon_w = style.icon_font:get_width(self.icon.code) + + if self.label ~= "" then + icon_w = icon_w + (self.padding.x / 2) + end + + local icon_h = style.icon_font:get_height() + (self.padding.y * 2) - border + + self.size.x = self.size.x + icon_w + self.size.y = math.max(self.size.y, icon_h) + end +end + +function Button:on_mouse_enter(...) + Button.super.on_mouse_enter(self, ...) + self.hover_text = style.accent + self.hover_back = style.line_highlight +end + +function Button:on_mouse_leave(...) + Button.super.on_mouse_leave(self, ...) + self.hover_text = nil + self.hover_back = nil +end + +function Button:on_scale_change(new_scale, prev_scale) + Button.super.on_scale_change(self, new_scale, prev_scale) + self.padding.x = self.padding.x * (new_scale / prev_scale) + self.padding.y = self.padding.y * (new_scale / prev_scale) +end + +function Button:update() + if not Button.super.update(self) then return false end + + -- update size + self:set_label(self.label) + + return true +end + +function Button:draw() + self.background_color = self.hover_back or style.background + + if not Button.super.draw(self) then return false end + + local font = self:get_font() + + local offsetx = self.position.x + self.padding.x + local offsety = self.position.y + local h = self:get_height() + local ih, th = style.icon_font:get_height(), font:get_height() + + if self.icon.code then + local normal = self.icon.color or style.text + local hover = self.icon.hover_color or style.accent + renderer.draw_text( + style.icon_font, + self.icon.code, + offsetx, + th > ih and (offsety + (h / 2)) - (ih/2) or (offsety + self.padding.y), + self.hover_text and hover or normal + ) + offsetx = offsetx + style.icon_font:get_width(self.icon.code) + (style.padding.x / 2) + end + + if self.label ~= "" then + renderer.draw_text( + font, + self.label, + offsetx, + ih > th and (offsety + (h / 2)) - (th/2) or (offsety + self.padding.y), + self.hover_text or self.foreground_color or style.text + ) + end + + return true +end + + +return Button diff --git a/debian/extra/libraries/widget/checkbox.lua b/debian/extra/libraries/widget/checkbox.lua new file mode 100644 index 0000000..357defa --- /dev/null +++ b/debian/extra/libraries/widget/checkbox.lua @@ -0,0 +1,142 @@ +-- +-- CheckBox Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local style = require "core.style" +local Widget = require "libraries.widget" + +---@class widget.checkbox : widget +---@overload fun(parent?:widget, label?:string):widget.checkbox +---@field private checked boolean +local CheckBox = Widget:extend() + +---Constructor +---@param parent widget +---@param label string +function CheckBox:new(parent, label) + CheckBox.super.new(self, parent) + self.type_name = "widget.checkbox" + self.checked = false + self:set_label(label or "") + self.animating = false + self.animating_color = style.caret +end + +---Set the checkbox label and recalculates the widget size. +---@param text string +function CheckBox:set_label(text) + CheckBox.super.set_label(self, text) + + local _, _, bw, _ = self:get_box_rect() + + local font = self:get_font() + + self.size.x = font:get_width(self.label) + bw + (style.padding.x / 2) + self.size.y = font:get_height() +end + +---Change the status of the checkbox. +---@param checked boolean +function CheckBox:set_checked(checked) + self.checked = checked + self:on_change(self.checked) +end + +---Get the status of the checkbox. +---@return boolean +function CheckBox:is_checked() + return self.checked +end + +---Called when the checkbox is (un)checked. +---@param checked boolean +function CheckBox:on_checked(checked) end + +function CheckBox:on_mouse_enter(...) + CheckBox.super.on_mouse_enter(self, ...) + self.hover_text = style.accent + self.hover_back = style.dim +end + +function CheckBox:on_mouse_leave(...) + CheckBox.super.on_mouse_leave(self, ...) + self.hover_text = nil + self.hover_back = nil +end + +function CheckBox:on_click() + self.checked = not self.checked + self:on_checked(self.checked) + self:on_change(self.checked) + + self.animating = true + self.animating_color = {table.unpack(style.caret)} + local target_color = {table.unpack(style.caret)} + + if self.checked then + self.animating_color[4] = 0 + target_color[4] = 255 + else + self.animating_color[4] = 255 + target_color[4] = 0 + end + self:animate(self.animating_color, {table.unpack(target_color)}, { + on_complete = function() + self.animating = false + end + }) +end + +function CheckBox:get_box_rect() + local size = 1.6 + local font = self:get_font() + local fh = font:get_height() / size + return + self.position.x, + self.position.y + (fh / (size * 2)), + font:get_width("x") + 4, + fh +end + +function CheckBox:update() + if not CheckBox.super.update(self) then return false end + + -- update size + self:set_label(self.label) + + return true +end + +function CheckBox:draw() + if not self:is_visible() then return false end + + local bx, by, bw, bh = self:get_box_rect() + + self:draw_border(bx, by, bw, bh) + + renderer.draw_rect( + bx, by, bw, bh, + self.hover_back or self.background_color or style.background + ) + + if self.animating then + renderer.draw_rect(bx + 2, by + 2, bw-4, bh-4, self.animating_color) + elseif self.checked then + renderer.draw_rect(bx + 2, by + 2, bw-4, bh-4, style.caret) + end + + renderer.draw_text( + self:get_font(), + self.label, + self.position.x + bw + (style.padding.x / 2), + self.position.y, + self.hover_text or self.foreground_color or style.text + ) + + return true +end + + +return CheckBox diff --git a/debian/extra/libraries/widget/colorpicker.lua b/debian/extra/libraries/widget/colorpicker.lua new file mode 100644 index 0000000..4e2563b --- /dev/null +++ b/debian/extra/libraries/widget/colorpicker.lua @@ -0,0 +1,745 @@ +-- +-- Color Picker Widget +-- Note: HSV and HSL conversion functions adapted from: +-- https://github.com/EmmanuelOga/columns/blob/master/utils/color.lua +-- which in turn was ported from: +-- http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c +-- +local core = require "core" +local style = require "core.style" +local common = require "core.common" +local Widget = require "libraries.widget" +local TextBox = require "libraries.widget.textbox" + +---@alias widget.colorpicker.colorrange renderer.color[] + +---The numerical portion of a color range on the hue selection bar. +---@type number +local HUE_COLOR_SEGMENT = 100 / 6 + +---Hue color ranges in the order rendered on the hue bar. +---@type widget.colorpicker.colorrange[] +local HUE_COLOR_RANGES = { + -- red -> yellow + { {255, 0, 0, 255}, {255, 255, 0, 255} }, + -- yellow -> green + { {255, 255, 0, 255}, {0, 255, 0, 255} }, + -- green -> cyan + { {0, 255 ,0, 255}, {0, 255, 255, 255} }, + -- cyan -> blue + { {0, 255, 255, 255}, {0, 0, 255, 255} }, + -- blue -> purple + { {0, 0, 255, 255}, {255, 0, 255, 255} }, + -- purple -> red + { {255, 0, 255, 255}, {255, 0, 0, 255} } +} + +---@type renderer.color +local COLOR_BLACK = {0, 0, 0, 255} + +---@type renderer.color +local COLOR_WHITE = {255, 255, 255, 255} + +---@class widget.colorpicker : widget +---@overload fun(parent:widget?, color?:renderer.color|string):widget.colorpicker +---@field hue_color renderer.color +---@field saturation_color renderer.color +---@field brightness_color renderer.color +---@field hue_pos number +---@field saturation_pos number +---@field brightness_pos number +---@field alpha number +---@field hue_mouse_down boolean +---@field saturation_mouse_down boolean +---@field brightness_mouse_down boolean +---@field html_notation widget.textbox +---@field rgba_notation widget.textbox +local ColorPicker = Widget:extend() + +---Constructor +---@param parent widget +---@param color? renderer.color | string +function ColorPicker:new(parent, color) + ColorPicker.super.new(self, parent, false) + + self.type_name = "widget.colorpicker" + + self.hue_pos = 0 + self.saturation_pos = 100 + self.brightness_pos = 100 + self.alpha = 255 + + self.hue_color = COLOR_BLACK + self.saturation_color = COLOR_BLACK + self.brightness_color = COLOR_BLACK + + self.hue_mouse_down = false; + self.saturation_mouse_down = false + self.brightness_mouse_down = false + + self.selector = { x = 0, y = 0, w = 0, h = 0 } + + self:set_border_width(0) + + local this = self + self.html_notation = TextBox(self, "#FF0000") + self.rgba_notation = TextBox(self, "rgba(255,0,0,1)") + self.html_updating = false + self.rgba_updating = false + + function self.html_notation:on_change(value) + if + not this.hue_mouse_down + and + not this.saturation_mouse_down + and + not this.brightness_mouse_down + and + not this.html_updating + then + this:set_color(value, true) + end + end + + function self.rgba_notation:on_change(value) + if + not this.hue_mouse_down + and + not this.saturation_mouse_down + and + not this.brightness_mouse_down + and + not this.rgba_updating + then + this:set_color(value, false, true) + end + end + + self:set_color(color or {255, 0, 0, 255}) + + -- set initial child positions and size + self:update_size() +end + +---Converts an RGB color value to HSL. Conversion formula +---adapted from http://en.wikipedia.org/wiki/HSL_color_space. +---Assumes r, g, and b are contained in the set [0, 255] and +---returns h, s, and l in the set [0, 1]. +---@param rgba renderer.color +---@return table hsla +function ColorPicker.rgb_to_hsl(rgba) + local r, g, b, a = rgba[1], rgba[2], rgba[3], rgba[4] + r, g, b = r / 255, g / 255, b / 255 + + local max, min = math.max(r, g, b), math.min(r, g, b) + local h, s, l + + l = (max + min) / 2 + + if max == min then + h, s = 0, 0 -- achromatic + else + local d = max - min + if l > 0.5 then s = d / (2 - max - min) else s = d / (max + min) end + if max == r then + h = (g - b) / d + if g < b then h = h + 6 end + elseif max == g then h = (b - r) / d + 2 + elseif max == b then h = (r - g) / d + 4 + end + h = h / 6 + end + + return {h, s, l, a and a/255 or 1} +end + +---Converts an HSL color value to RGB. Conversion formula +---adapted from http://en.wikipedia.org/wiki/HSL_color_space. +---Assumes h, s, and l are contained in the set [0, 1] and +---returns r, g, and b in the set [0, 255]. +---@param h number The hue +---@param s number The saturation +---@param l number The lightness +---@param a number The alpha +---@return renderer.color rgba +function ColorPicker.hsl_to_rgb(h, s, l, a) + local r, g, b + + if s == 0 then + r, g, b = l, l, l -- achromatic + else + local function hue2rgb(p, q, t) + if t < 0 then t = t + 1 end + if t > 1 then t = t - 1 end + if t < 1/6 then return p + (q - p) * 6 * t end + if t < 1/2 then return q end + if t < 2/3 then return p + (q - p) * (2/3 - t) * 6 end + return p + end + + local q + if l < 0.5 then q = l * (1 + s) else q = l + s - l * s end + local p = 2 * l - q + + r = hue2rgb(p, q, h + 1/3) + g = hue2rgb(p, q, h) + b = hue2rgb(p, q, h - 1/3) + end + + return {r * 255, g * 255, b * 255, a * 255} +end + +---Converts an RGB color value to HSV. Conversion formula +---adapted from http://en.wikipedia.org/wiki/HSV_color_space. +---Assumes r, g, and b are contained in the set [0, 255] and +---returns h, s, and v in the set [0, 1]. +---@param rgba renderer.color +---@return table hsva The HSV representation +function ColorPicker.rgb_to_hsv(rgba) + local r, g, b, a = rgba[1], rgba[2], rgba[3], rgba[4] + r, g, b, a = r / 255, g / 255, b / 255, a / 255 + local max, min = math.max(r, g, b), math.min(r, g, b) + local h, s, v + v = max + + local d = max - min + if max == 0 then s = 0 else s = d / max end + + if max == min then + h = 0 -- achromatic + else + if max == r then + h = (g - b) / d + if g < b then h = h + 6 end + elseif max == g then h = (b - r) / d + 2 + elseif max == b then h = (r - g) / d + 4 + end + h = h / 6 + end + + return {h, s, v, a/255} +end + +---Converts an HSV color value to RGB. Conversion formula +---adapted from http://en.wikipedia.org/wiki/HSV_color_space. +---Assumes h, s, and v are contained in the set [0, 1] and +---returns r, g, and b in the set [0, 255]. +---@param h number The hue +---@param s number The saturation +---@param v number The brightness +---@param a number The alpha +---@return renderer.color rgba The RGB representation +function ColorPicker.hsv_to_rgb(h, s, v, a) + local r, g, b + + local i = math.floor(h * 6); + local f = h * 6 - i; + local p = v * (1 - s); + local q = v * (1 - f * s); + local t = v * (1 - (1 - f) * s); + + i = i % 6 + + if i == 0 then r, g, b = v, t, p + elseif i == 1 then r, g, b = q, v, p + elseif i == 2 then r, g, b = p, v, t + elseif i == 3 then r, g, b = p, q, v + elseif i == 4 then r, g, b = t, p, v + elseif i == 5 then r, g, b = v, p, q + end + + return {math.ceil(r * 255), math.ceil(g * 255), math.ceil(b * 255), math.ceil(a * 255)} +end + +---Converts a css format color string into a renderer.color if possible, +---if conversion fails returns nil. Adapted from colorpreview plugin. +---@param color string +---@return renderer.color? color +function ColorPicker.color_from_string(color) + local s, e, r, g, b, a, base, nibbles; + + s, e, r, g, b, a = color:find("#(%x%x)(%x%x)(%x%x)(%x?%x?)") + + if s then + base = 16 + else + s, e, r, g, b, a = color:find("#(%x)(%x)(%x)") + + if s then + base = 16 + nibbles = true + else + s, e, r, g, b, a = color:find( + "rgba?%((%d+)%D+(%d+)%D+(%d+)[%s,]-([%.%d]-)%s-%)" + ) + end + end + + if not s then return nil end + + r = tonumber(r or "", base) + g = tonumber(g or "", base) + b = tonumber(b or "", base) + + a = tonumber(a or "", base) + if a ~= nil then + if base ~= 16 then + a = a * 0xff + end + else + a = 0xff + end + + if nibbles then + r = r * 16 + g = g * 16 + b = b * 16 + end + + return {r, g, b, a} +end + +---Gets a color between two given colors on the position +---defined by the given percent. +---@param from_color renderer.color +---@param to_color renderer.color +---@param percent number +---@return renderer.color color +function ColorPicker.color_in_between(from_color, to_color, percent) + local color = {} + for i=1, 4 do + if from_color[i] == to_color[i] then + color[i] = from_color[i] + else + color[i] = common.clamp( + from_color[i] + math.floor((to_color[i] - from_color[i]) * percent), + 0, + 255 + ) + end + end + return color +end + +function ColorPicker:get_name() + return "Color Picker" +end + +---Gets the currently selected color on the hue bar. +---@return renderer.color +function ColorPicker:get_hue_color() + local w = self.selector.w + local pos = self.hue_pos + local pos_percent = pos / 100 + local range_size = w / 6 + local range + if pos <= (HUE_COLOR_SEGMENT) then + range = 1 + elseif pos <= (HUE_COLOR_SEGMENT) * 2 then + range = 2 + elseif pos <= (HUE_COLOR_SEGMENT) * 3 then + range = 3 + elseif pos <= (HUE_COLOR_SEGMENT) * 4 then + range = 4 + elseif pos <= (HUE_COLOR_SEGMENT) * 5 then + range = 5 + else + range = 6 + end + local range_position = (w * pos_percent) - ((range_size * range)-range_size) + local range_percent = range_position / range_size + return ColorPicker.color_in_between( + HUE_COLOR_RANGES[range][1], + HUE_COLOR_RANGES[range][2], + range_percent + ) +end + +---Gets the currently selected color on the saturation bar. +---@return renderer.color +function ColorPicker:get_saturation_color() + local w = self.selector.w + local pos = self.saturation_pos + local pos_percent = pos / 100 + local range_size = w + local range, color1, color2 = 1, COLOR_WHITE, self.hue_color + local range_position = (w * pos_percent) - ((range_size * range)-range_size) + local range_percent = range_position / range_size + return ColorPicker.color_in_between(color1, color2, range_percent) +end + +---Gets the currently selected color on the brightness bar. +---@return renderer.color +function ColorPicker:get_brightness_color() + local w = self.selector.w + local pos = self.brightness_pos + local pos_percent = pos / 100 + local range_size = w + local range, color1, color2 = 1, COLOR_BLACK, self.saturation_color + local range_position = (w * pos_percent) - ((range_size * range)-range_size) + local range_percent = range_position / range_size + return ColorPicker.color_in_between(color1, color2, range_percent) +end + +---Gets the currently selected rgba color. +---@return renderer.color +function ColorPicker:get_color() + return ColorPicker.hsv_to_rgb( + self.hue_pos / 100, + self.saturation_pos / 100, + self.brightness_pos / 100, + self.alpha / 255 + ) +end + +---Set current color from rgba source which can also +---be a css string representation. +---@param color renderer.color | string +function ColorPicker:set_color(color, skip_html, skip_rgba) + -- we set the color on a coroutine in case it is been set before + -- the control is properly initialized like the constructor. + core.add_thread(function() + if type(color) == "string" then + color = ColorPicker.color_from_string(color) + end + + if not color then color = {255, 0, 0, 255} end + + local hsva = ColorPicker.rgb_to_hsv(color) + + self.hue_pos = hsva[1] * 100 + self.saturation_pos = hsva[2] * 100 + self.brightness_pos = hsva[3] * 100 + + self.hue_color = self:get_hue_color() + self.saturation_color = self:get_saturation_color() + self.brightness_color = self:get_brightness_color() + self.alpha = color[4] + + if not skip_html then + self.html_updating = true + self.html_notation:set_text(string.format( + "#%02X%02X%02X%02X", + color[1], color[2], color[3], color[4] + )) + self.html_updating = false + end + + if not skip_rgba then + self.rgba_updating = true + self.rgba_notation:set_text(string.format( + "rgba(%d,%d,%d,%.2f)", + color[1], color[2], color[3], color[4] / 255 + )) + self.rgba_updating = false + end + + self:on_change(color) + end) +end + +---Set the transparency level, the lower the given alpha the more transparent. +---@param alpha number A value from 0 to 255 +function ColorPicker:set_alpha(alpha) + self.alpha = common.clamp(alpha, 0, 255) +end + +---Draw a hue color bar at given location and size. +---@param x number +---@param y number +---@param w number +---@param h number +function ColorPicker:draw_hue(x, y, w, h) + local sx = x + local step = 1 + local cwidth = 1 + local cheight = h or 10 + + if w < 255*6 then + step = 255 / (w / 6) + else + cwidth = (w / 6) / 255 + end + + -- red -> yellow + for g=0, 255, step do + renderer.draw_rect(x, y, cwidth, cheight, {255, g, 0, 255}) + x = x + cwidth + end + + -- yellow -> green + for r=255, 0, -step do + renderer.draw_rect(x, y, cwidth, cheight, {r, 255, 0, 255}) + x = x + cwidth + end + + -- green -> cyan + for b=0, 255, step do + renderer.draw_rect(x, y, cwidth, cheight, {0, 255, b, 255}) + x = x + cwidth + end + + -- cyan -> blue + for g=255, 0, -step do + renderer.draw_rect(x, y, cwidth, cheight, {0, g, 255, 255}) + x = x + cwidth + end + + -- blue -> purple + for r=0, 255, step do + renderer.draw_rect(x, y, cwidth, cheight, {r, 0, 255, 255}) + x = x + cwidth + end + + -- purple -> red + for b=255, 0, -step do + renderer.draw_rect(x, y, cwidth, cheight, {255, 0, b, 255}) + x = x + cwidth + end + + sx = sx + (w * (self.hue_pos / 100)) + self:draw_selector(sx, y, cheight, self.hue_color) +end + +---Draw a saturation color bar at given location and size. +---@param x number +---@param y number +---@param w number +---@param h number +function ColorPicker:draw_saturation(x, y, w, h) + local sx = x + local step = 1 + local cwidth = 1 + local cheight = h or 10 + + if w < 255 then + step = 255 / w + else + cwidth = w / 255 + end + + -- white to base + for i=0, 255, step do + local color = ColorPicker.color_in_between(COLOR_WHITE, self.hue_color, i / 255) + renderer.draw_rect(x, y, cwidth, cheight, color) + x = x + cwidth + end + + sx = sx + (w * (self.saturation_pos / 100)) + self:draw_selector(sx, y, cheight, self.saturation_color) +end + +---Draw a brightness color bar at given location and size. +---@param x number +---@param y number +---@param w number +---@param h number +function ColorPicker:draw_brightness(x, y, w, h) + local sx = x + local step = 1 + local cwidth = 1 + local cheight = h or 10 + + if w < 255 then + step = 255 / w + else + cwidth = w / 255 + end + + -- black to base + for i=0, 255, step do + local color = ColorPicker.color_in_between(COLOR_BLACK, self.saturation_color, i / 255) + renderer.draw_rect(x, y, cwidth, cheight, color) + x = x + cwidth + end + + sx = sx + (w * (self.brightness_pos / 100)) + self:draw_selector(sx, y, cheight, self.brightness_color) +end + +---@param self widget.colorpicker +local function update_control_values(self) + local color = self:get_color() + self.alpha = color[4] + self.html_updating = true + self.rgba_updating = true + self.html_notation:set_text(string.format( + "#%02X%02X%02X%02X", + color[1], color[2], color[3], color[4] + )) + self.rgba_notation:set_text(string.format( + "rgba(%d,%d,%d,%.2f)", + color[1], color[2], color[3], color[4] / 255 + )) + self.html_updating = false + self.rgba_updating = false + self:on_change(color) +end + +function ColorPicker:on_mouse_pressed(button, x, y, clicks) + if not ColorPicker.super.on_mouse_pressed(self, button, x, y, clicks) then + return false + end + + if + x >= self.selector.x and x <= self.selector.x + self.selector.w + and + y >= self.selector.y and y <= self.selector.y + self.selector.h + then + local sx, sw = self.selector.x, self.selector.w + self.hue_pos = common.clamp(x, sx, sx + sw) + self.hue_pos = ((self.hue_pos - self.selector.x) / self.selector.w) * 100 + self.hue_color = self:get_hue_color() + self.saturation_color = self:get_saturation_color() + self.hue_mouse_down = true + elseif + x >= self.selector.x and x <= self.selector.x + self.selector.w + and + y >= self.selector.y + style.padding.y + self.selector.h + and + y <= self.selector.y + style.padding.y + (self.selector.h * 2) + then + local sx, sw = self.selector.x, self.selector.w + self.saturation_pos = common.clamp(x, sx, sx + sw) + self.saturation_pos = ((self.saturation_pos - self.selector.x) / self.selector.w) * 100 + self.saturation_color = self:get_saturation_color() + self.brightness_color = self:get_brightness_color() + self.saturation_mouse_down = true + elseif + x >= self.selector.x and x <= self.selector.x + self.selector.w + and + y >= self.selector.y + style.padding.y * 2 + self.selector.h * 2 + and + y <= self.selector.y + style.padding.y * 2 + (self.selector.h * 4) + then + local sx, sw = self.selector.x, self.selector.w + self.brightness_pos = common.clamp(x, sx, sx + sw) + self.brightness_pos = ((self.brightness_pos - self.selector.x) / self.selector.w) * 100 + self.brightness_color = self:get_brightness_color() + self.brightness_mouse_down = true + end + if self.hue_mouse_down or self.saturation_mouse_down or self.brightness_mouse_down then + self:capture_mouse() + update_control_values(self) + end + return true +end + +function ColorPicker:on_mouse_released(button, x, y) + if self.hue_mouse_down or self.saturation_mouse_down or self.brightness_mouse_down then + self:release_mouse() + end + + self.hue_mouse_down = false + self.saturation_mouse_down = false + self.brightness_mouse_down = false + + if not ColorPicker.super.on_mouse_released(self, button, x, y) then + return false + end + + return true +end + +function ColorPicker:on_mouse_moved(x, y, dx, dy) + if self.hue_mouse_down then + local sx, sw = self.selector.x, self.selector.w + self.hue_pos = common.clamp(x, sx, sx + sw) + self.hue_pos = ((self.hue_pos - self.selector.x) / self.selector.w) * 100 + self.hue_color = self:get_hue_color() + self.saturation_color = self:get_saturation_color() + self.brightness_color = self:get_brightness_color() + elseif self.saturation_mouse_down then + local sx, sw = self.selector.x, self.selector.w + self.saturation_pos = common.clamp(x, sx, sx + sw) + self.saturation_pos = ((self.saturation_pos - self.selector.x) / self.selector.w) * 100 + self.saturation_color = self:get_saturation_color() + self.brightness_color = self:get_brightness_color() + elseif self.brightness_mouse_down then + local sx, sw = self.selector.x, self.selector.w + self.brightness_pos = common.clamp(x, sx, sx + sw) + self.brightness_pos = ((self.brightness_pos - self.selector.x) / self.selector.w) * 100 + self.brightness_color = self:get_brightness_color() + end + if self.hue_mouse_down or self.saturation_mouse_down or self.brightness_mouse_down then + update_control_values(self) + else + return ColorPicker.super.on_mouse_moved(self, x, y, dx, dy) + end + return true +end + +function ColorPicker:update_size() + self.selector.h = 10 * SCALE + local x, y = 0, style.padding.y * 3 + self.selector.h * 4 + self.html_notation:set_position(x, y) + self.rgba_notation:set_position(self.html_notation:get_right() + style.padding.x, y) + if self:get_width() < self.rgba_notation:get_right() then + self:set_size(self.rgba_notation:get_right() + style.padding.x) + end + if self:get_height() < self.rgba_notation:get_bottom() then + self:set_size(nil, self.rgba_notation:get_bottom() + style.padding.y) + end +end + +function ColorPicker:update() + if not ColorPicker.super.update(self) then return false end + self:update_size() + return true +end + +function ColorPicker:draw_selector(x, y, h, color) + local border = 2 * SCALE + x = x - border - ((10 * SCALE) / border) + y = y - border + renderer.draw_rect(x, y, 14 * SCALE, h + (border * 2), COLOR_WHITE) + renderer.draw_rect(x+border, y + border, 10 * SCALE, h, color) +end + +function ColorPicker:draw() + if not ColorPicker.super.draw(self) then return false end + + local x, y, w = self.position.x, self.position.y, self.size.x + + self.selector.x = x + self.selector.y = style.padding.y + y + self.selector.w = w - style.padding.x - 100 + self.selector.h = 10 * SCALE + + self:draw_hue( + self.selector.x, + self.selector.y, + self.selector.w, + self.selector.h + ) + + self:draw_saturation( + self.selector.x, + self.selector.y + style.padding.y + self.selector.h, + self.selector.w, + self.selector.h + ) + + self:draw_brightness( + self.selector.x, + self.selector.y + style.padding.y * 2 + self.selector.h * 2, + self.selector.w, + self.selector.h + ) + + local c = self:get_color() + + renderer.draw_rect( + self.selector.x + style.padding.x + self.selector.w, + self.selector.y, + 100, + (self.selector.y + style.padding.y * 2 + self.selector.h * 3) + - self.selector.y, + c + ) + + return true +end + + +return ColorPicker diff --git a/debian/extra/libraries/widget/colorpickerdialog.lua b/debian/extra/libraries/widget/colorpickerdialog.lua new file mode 100644 index 0000000..a88dc80 --- /dev/null +++ b/debian/extra/libraries/widget/colorpickerdialog.lua @@ -0,0 +1,77 @@ +-- +-- Color Picker Dialog Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local style = require "core.style" +local Button = require "libraries.widget.button" +local ColorPicker = require "libraries.widget.colorpicker" +local Dialog = require "libraries.widget.dialog" + +---@class widget.colorpickerdialog : widget.dialog +---@overload fun(title?:string, color?:renderer.color|string):widget.colorpickerdialog +---@field super widget.dialog +---@field picker widget.colorpicker +---@field apply widget.button +---@field cancel widget.button +local ColorPickerDialog = Dialog:extend() + +---Constructor +---@param title? string +---@param color? renderer.color | string +function ColorPickerDialog:new(title, color) + ColorPickerDialog.super.new(self, title or "Color Picker") + + self.type_name = "widget.colorpickerdialog" + self.picker = ColorPicker(self.panel, color) + + local this = self + + self.apply = Button(self.panel, "Apply") + self.apply:set_icon("S") + function self.apply:on_click() + this:on_apply(this.picker:get_color()) + this:on_close() + end + + self.cancel = Button(self.panel, "Cancel") + self.cancel:set_icon("C") + function self.cancel:on_click() + this:on_close() + end +end + +---Called when the user clicks on apply +---@param value renderer.color +function ColorPickerDialog:on_apply(value) end + +function ColorPickerDialog:update() + if not ColorPickerDialog.super.update(self) then return false end + + self.picker:set_position(style.padding.x/2, 0) + + self.apply:set_position( + style.padding.x/2, + self.picker:get_bottom() + style.padding.y + ) + self.cancel:set_position( + self.apply:get_right() + style.padding.x, + self.picker:get_bottom() + style.padding.y + ) + + self.panel.size.x = self.panel:get_real_width() + style.padding.x + self.panel.size.y = self.panel:get_real_height() + self.size.x = self:get_real_width() - (style.padding.x / 2) + self.size.y = self:get_real_height() + (style.padding.y / 2) + + self.close:set_position( + self.size.x - self.close.size.x - (style.padding.x / 2), + style.padding.y / 2 + ) + + return true +end + + +return ColorPickerDialog diff --git a/debian/extra/libraries/widget/dialog.lua b/debian/extra/libraries/widget/dialog.lua new file mode 100644 index 0000000..4f27b4b --- /dev/null +++ b/debian/extra/libraries/widget/dialog.lua @@ -0,0 +1,164 @@ +-- +-- Dialog object that serves as base to implement other dialogs. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local core = require "core" +local style = require "core.style" +local Widget = require "libraries.widget" +local Button = require "libraries.widget.button" +local Label = require "libraries.widget.label" + +---@class widget.dialog : widget +---@overload fun(title?:string):widget.dialog +---@field protected title widget.label +---@field protected close widget.button +---@field protected panel widget +local Dialog = Widget:extend() + +---Constructor +---@param title string +function Dialog:new(title) + Dialog.super.new(self) + + self.type_name = "widget.dialog" + + self.draggable = true + self.scrollable = false + + -- minimum width and height + self.size.mx = 400 + self.size.my = 150 + + self.title = Label(self, "") + self.close = Button(self, "") + self.close:set_icon("X") + self.close.border.width = 0 + self.close:toggle_background(false) + self.close.padding.x = 4 + self.close.padding.y = 0 + self.panel = Widget(self) + self.panel.border.width = 0 + self.panel.scrollable = true + + local this = self + + function self.close:on_click() + this:on_close() + this:hide() + end + + self:set_title(title or "") +end + +---Returns the widget where you can add child widgets to this dialog. +---@return widget +function Dialog:get_panel() + return self.panel +end + +---Change the dialog title. +---@param text string|widget.styledtext +function Dialog:set_title(text) + self.title:set_label(text) +end + +---Calculate the dialog size, centers it relative to screen and shows it. +function Dialog:show() + Dialog.super.show(self) + self:update() + self:centered() +end + +---Called when the user clicks the close button of the dialog. +function Dialog:on_close() + self:hide() +end + +function Dialog:update() + if not Dialog.super.update(self) then return false end + + local width = math.max( + self.title:get_width() + (style.padding.x * 3) + self.close:get_width(), + self.size.mx, + self.size.x + ) + + local height = math.max( + self.title:get_height() + (style.padding.y * 3), + self.size.my, + self.size.y + ) + + self:set_size(width, height) + + self.title:set_position( + style.padding.x / 2, + style.padding.y / 2 + ) + + self.close:set_position( + self.size.x - self.close.size.x - (style.padding.x / 2), + style.padding.y / 2 + ) + + self.panel:set_position( + 0, + self.title:get_bottom() + (style.padding.y / 2) + ) + + self.panel:set_size( + self.size.x, + self.size.y - self.title.size.y - style.padding.y + ) + + return true +end + +---We overwrite default draw function to draw the title background. +function Dialog:draw() + if not self:is_visible() then return false end + + Dialog.super.draw(self) + + self:draw_border() + + if self.background_color then + self:draw_background(self.background_color) + else + self:draw_background( + self.parent and style.background or style.background2 + ) + end + + if #self.childs > 0 then + core.push_clip_rect( + self.position.x, + self.position.y, + self.size.x, + self.size.y + ) + end + + -- draw the title background + renderer.draw_rect( + self.position.x, + self.position.y, + self.size.x, self.title:get_height() + style.padding.y, + style.selection + ) + + for i=#self.childs, 1, -1 do + self.childs[i]:draw() + end + + if #self.childs > 0 then + core.pop_clip_rect() + end + + return true +end + + +return Dialog diff --git a/debian/extra/libraries/widget/filepicker.lua b/debian/extra/libraries/widget/filepicker.lua new file mode 100644 index 0000000..c37af81 --- /dev/null +++ b/debian/extra/libraries/widget/filepicker.lua @@ -0,0 +1,395 @@ +local core = require "core" +local common = require "core.common" +local style = require "core.style" +local Widget = require "libraries.widget" +local Button = require "libraries.widget.button" +local Label = require "libraries.widget.label" + +---@class widget.filepicker : widget +---@overload fun(parent?:widget, path?:string):widget.filepicker +---@field public pick_mode integer +---@field public filters table +---@field private path string +---@field private file widget.label +---@field private textbox widget.textbox +---@field private button widget.button +local FilePicker = Widget:extend() + +---Operation modes for the file picker. +---@type table +FilePicker.mode = { + ---Opens file browser the selected file does not has to exist. + FILE = 1, + ---Opens file browser the selected file has to exist. + FILE_EXISTS = 2, + ---Opens directory browser the selected directory does not has to exist. + DIRECTORY = 4, + ---Opens directory browser the selected directory has to exist. + DIRECTORY_EXISTS = 8 +} + +---@param text string +local function suggest_directory(text) + text = common.home_expand(text) + return common.home_encode_list(common.dir_path_suggest(text)) +end + +---@param path string +local function check_directory_path(path) + local abs_path = system.absolute_path(path) + local info = abs_path and system.get_file_info(abs_path) + if not info or info.type ~= 'dir' then return nil end + return abs_path +end + +---@param str string +---@param find string +---@param replace string +local function str_replace(str, find, replace) + local start, ending = str:find(find, 1, true) + if start == 1 then + return replace .. str:sub(ending + 1) + else + return str:sub(1, start - 1) .. replace .. str:sub(ending + 1) + end +end + +---@alias widget.filepicker.modes +---| `FilePicker.mode.FILE` +---| `FilePicker.mode.FILE_EXISTS` +---| `FilePicker.mode.DIRECTORY` +---| `FilePicker.mode.DIRECTORY_EXISTS` + +---Constructor +---@param parent widget +---@param path? string +function FilePicker:new(parent, path) + FilePicker.super.new(self, parent) + + local this = self + + self.type_name = "widget.filepicker" + + self.filters = {} + self.border.width = 0 + self.pick_mode = FilePicker.mode.FILE + + self.file = Label(self, "") + self.file.clickable = true + self.file:set_border_width(1) + function self.file:on_click(button) + if button == "left" then + this:show_picker() + end + end + function self.file:on_mouse_enter(...) + Label.super.on_mouse_enter(self, ...) + self.border.color = style.caret + end + function self.file:on_mouse_leave(...) + Label.super.on_mouse_leave(self, ...) + self.border.color = style.text + end + + self.button = Button(self, "") + self.button:set_icon("D") + self.button:set_tooltip("open file browser") + function self.button:on_click(button) + if button == "left" then + this:show_picker() + end + end + + local label_width = self.file:get_width() + if label_width <= 10 then + label_width = 200 + (self.file.border.width * 2) + self.file:set_size(200, self.button:get_height() - self.button.border.width * 2) + end + + self:set_size( + label_width + self.button:get_width(), + math.max(self.file:get_height(), self.button:get_height()) + ) + + self:set_path(path) +end + +---Set the filepicker size +---@param width? number +---@param height? number +function FilePicker:set_size(width, height) + FilePicker.super.set_size(self, width, height) + + self.file:set_position(0, 0) + self.file:set_size( + self:get_width() - self.button:get_width(), + self.button:get_height() + ) + + self.button:set_position(self.file:get_right(), 0) + + self.size.y = math.max( + self.file:get_height(), + self.button:get_height() + -- something is off on calculation since adding border width should not + -- be needed to display whole rendered control at all... + ) + self.button.border.width +end + +---Add a lua pattern to the filters list +---@param pattern string +function FilePicker:add_filter(pattern) + table.insert(self.filters, pattern) +end + +---Clear the filters list +function FilePicker:clear_filters() + self.filters = {} +end + +---Set the operation mode for the file picker. +---@param mode widget.filepicker.modes | string | integer +function FilePicker:set_mode(mode) + if type(mode) == "string" then + ---@type integer + local intmode = FilePicker.mode[mode:upper()] + self.pick_mode = intmode + else + self.pick_mode = mode + end +end + +---Set the full path including directory and filename. +---@param path? string +function FilePicker:set_path(path) + if path then + self.path = path or "" + if common.path_belongs_to(path, core.project_dir) then + self.file.label = path ~= "" and + common.relative_path(core.project_dir, path) + or + "" + else + self.file.label = path + end + else + self.path = "" + self.file.label = "" + end +end + +---Get the full path including directory and filename. +---@return string | nil +function FilePicker:get_path() + if self.path ~= "" then + return self.path + end + return nil +end + +---Get the full path relative to current project dir or absolute if it doesn't +---belongs to the current project directory. +---@return string +function FilePicker:get_relative_path() + if + self.path ~= "" + and + common.path_belongs_to(self.path, core.project_dir) + then + return common.relative_path(core.project_dir, self.path) + end + return self.path or "" +end + +---Set the filename part only. +---@param name string +function FilePicker:set_filename(name) + local dir_part = common.dirname(self.path) + if dir_part then + self:set_path(dir_part .. PATHSEP .. name) + else + self:set_path(name) + end +end + +---Get the filename part only. +---@return string | nil +function FilePicker:get_filename() + local dir_part = common.dirname(self.path) + if dir_part then + local filename = str_replace(self.path, dir_part .. PATHSEP, "") + return filename + elseif self.path ~= "" then + return self.path + end + return nil +end + +---Set the directory part only. +---@param dir string +function FilePicker:set_directory(dir) + local filename = self:get_filename() + if filename then + self:set_path(dir:gsub("[\\/]$", "") .. PATHSEP .. filename) + else + self:set_path(dir:gsub("[\\/]$", "")) + end +end + +---Get the directory part only. +---@return string | nil +function FilePicker:get_directory() + if self.path ~= "" then + local dir_part = common.dirname(self.path) + if dir_part then return dir_part end + end + return nil +end + +---Filter a list of directories by applying currently set filters. +---@param self widget.filepicker +---@param list table +---@return table +local function filter(self, list) + if #self.filters > 0 then + local new_list = {} + for _, value in ipairs(list) do + if common.match_pattern(value, self.filters) then + table.insert(new_list, value) + elseif + self.pick_mode == FilePicker.mode.FILE + or + self.pick_mode == FilePicker.mode.FILE_EXISTS + then + local path = common.home_expand(value) + local abs_path = check_directory_path(path) + if abs_path then + table.insert(new_list, value) + end + end + end + return new_list + end + return list +end + +---@param self widget.filepicker +local function show_file_picker(self) + core.command_view:enter("Choose File", { + text = self:get_relative_path(), + submit = function(text) + ---@type string + local filename = text + local dirname = common.dirname(common.home_expand(text)) + if dirname then + filename = common.home_expand(text) + filename = system.absolute_path(dirname) + .. PATHSEP + .. str_replace(filename, dirname .. PATHSEP, "") + elseif filename ~= "" then + filename = core.project_dir .. PATHSEP .. filename + end + self:set_path(filename) + self:on_change(filename ~= "" and filename or nil) + end, + suggest = function (text) + return filter( + self, + common.home_encode_list(common.path_suggest(common.home_expand(text))) + ) + end, + validate = function(text) + if #self.filters > 0 and text ~= "" and not common.match_pattern(text, self.filters) then + core.error( + "File does not match the filters: %s", + table.concat(self.filters, ", ") + ) + return false + end + local filename = common.home_expand(text) + local path_stat, err = system.get_file_info(filename) + if path_stat and path_stat.type == 'dir' then + core.error("Cannot open %s, is a folder", text) + return false + end + if self.pick_mode == FilePicker.mode.FILE_EXISTS then + if not path_stat then + core.error("Cannot open file %s: %s", text, err) + return false + end + else + local dirname = common.dirname(filename) + local dir_stat = dirname and system.get_file_info(dirname) + if dirname and not dir_stat then + core.error("Directory does not exists: %s", dirname) + return false + end + end + return true + end, + }) +end + +---@param self widget.filepicker +local function show_dir_picker(self) + core.command_view:enter("Choose Directory", { + text = self:get_relative_path(), + submit = function(text) + local path = common.home_expand(text) + local abs_path = check_directory_path(path) + self:set_path(abs_path or text) + self:on_change(abs_path or (text ~= "" and text or nil)) + end, + suggest = function(text) + return filter(self, suggest_directory(text)) + end, + validate = function(text) + if #self.filters > 0 and text ~= "" and not common.match_pattern(text, self.filters) then + core.error( + "Directory does not match the filters: %s", + table.concat(self.filters, ", ") + ) + return false + end + if self.pick_mode == FilePicker.mode.DIRECTORY_EXISTS then + local path = common.home_expand(text) + local abs_path = check_directory_path(path) + if not abs_path then + core.error("Cannot open directory %q", path) + return false + end + end + return true + end + }) +end + +---Show the command view file or directory browser depending on the +---current file picker mode. +function FilePicker:show_picker() + if + self.pick_mode == FilePicker.mode.FILE + or + self.pick_mode == FilePicker.mode.FILE_EXISTS + then + show_file_picker(self) + else + show_dir_picker(self) + end +end + +function FilePicker:update() + if not FilePicker.super.update(self) then return false end + + if self:get_width() ~= (self.file:get_width() + self.button:get_width()) then + self:set_size( + self.file:get_width() + self.button:get_width(), + self.button:get_height() + ) + end + + return true +end + + +return FilePicker diff --git a/debian/extra/libraries/widget/foldingbook.lua b/debian/extra/libraries/widget/foldingbook.lua new file mode 100644 index 0000000..1b456a3 --- /dev/null +++ b/debian/extra/libraries/widget/foldingbook.lua @@ -0,0 +1,216 @@ +-- +-- FoldingBook Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local style = require "core.style" +local Widget = require "libraries.widget" +local Button = require "libraries.widget.button" + +---Represents a foldingbook pane +---@class widget.foldingbook.pane +---@field public name string +---@field public tab widget.button +---@field public container widget +---@field public expanded boolean +local FoldingBookPane = {} + +---@class widget.foldingbook : widget +---@overload fun(parent:widget?):widget.foldingbook +---@field public panes widget.foldingbook.pane[] +local FoldingBook = Widget:extend() + +---FoldingBook constructor +---@param parent widget +function FoldingBook:new(parent) + FoldingBook.super.new(self, parent) + self.type_name = "widget.foldingbook" + self.panes = {} + self.scrollable = true +end + +---@param pane widget.foldingbook.pane +function FoldingBook:on_tab_click(pane) + pane.expanded = not pane.expanded +end + +---Adds a new pane to the foldingbook and returns a container widget where +---you can add more child elements. +---@param name string +---@param label string +---@return widget container +function FoldingBook:add_pane(name, label) + ---@type widget.button + local tab = Button(self, label) + tab.border.width = 0 + tab:toggle_expand(true) + tab:set_icon("+") + + if #self.panes > 0 then + if self.panes[#self.panes].expanded then + tab:set_position(0, self.panes[#self.panes].container:get_bottom() + 2) + else + tab:set_position(0, self.panes[#self.panes].tab:get_bottom() + 2) + end + else + tab:set_position(0, 10) + end + + local container = Widget(self) + container:set_position(0, tab:get_bottom() + 4) + container:set_size(self:get_width(), 0) + + local pane = { + name = name, + tab = tab, + container = container, + expanded = false + } + + tab.on_click = function() + self:on_tab_click(pane) + end + + table.insert(self.panes, pane) + + return container +end + +---@param name string +---@return widget.foldingbook.pane | nil +function FoldingBook:get_pane(name) + for _, pane in pairs(self.panes) do + if pane.name == name then + return pane + end + end + return nil +end + +---Delete a pane and all its childs from the folding book. +---@param name string +---@return boolean deleted +function FoldingBook:delete_pane(name) + for idx, pane in ipairs(self.panes) do + if pane.name == name then + self:remove_child(pane.tab) + self:remove_child(pane.container) + table.remove(self.panes, idx) + return true + end + end + return false +end + +---Activates the given pane +---@param name string +---@param visible boolean | nil +function FoldingBook:toggle_pane(name, visible) + local pane = self:get_pane(name) + if pane then + if type(visible) == "boolean" then + pane.expanded = visible + else + pane.expanded = not pane.expanded + end + end +end + +---Change the tab label of the given pane. +---@param name string +---@param label string +function FoldingBook:set_pane_label(name, label) + local pane = self:get_pane(name) + if pane then + pane.tab:set_label(label) + return true + end + return false +end + +---Set or remove the icon for the given pane. +---@param name string +---@param icon string +---@param color? renderer.color|nil +---@param hover_color? renderer.color|nil +function FoldingBook:set_pane_icon(name, icon, color, hover_color) + local pane = self:get_pane(name) + if pane then + pane.tab:set_icon(icon, color, hover_color) + return true + end + return false +end + +---Recalculate the position of the elements on resizing or position changes. +function FoldingBook:update() + if not FoldingBook.super.update(self) then return false end + + ---@type widget.foldingbook.pane + local prev_pane = nil + + for _, pane in ipairs(self.panes) do + local tx, ty = 0, 10 + local cx, cy = 0, 0 + local cw, ch = 0, 0 + + if prev_pane then + if prev_pane and prev_pane.container:is_visible() then + ty = prev_pane.container:get_bottom() + 2 + else + ty = prev_pane.tab:get_bottom() + 2 + end + end + + pane.tab:set_position(tx, ty) + + cy = pane.tab:get_bottom() + 4 + cw = self:get_width() + if #pane.container.childs > 0 then + ch = pane.container:get_real_height() + 10 + end + + pane.container.border.color = style.divider + + if pane.expanded and not pane.container.hiding then + pane.container:set_position(cx, cy) + pane.container:set_size(cw) + if not pane.container.visible then + pane.container:set_size(cw, ch) + pane.container:show_animated(true) + pane.tab:set_icon("-") + pane.container.hiding = false + end + elseif pane.container.visible and not pane.container.hiding then + pane.tab:set_icon("+") + pane.container.hiding = true + pane.container:hide_animated(true, false, { + on_complete = function() + pane.container.hiding = false + end + }) + end + + prev_pane = pane + end + + return true +end + +---Here we draw the bottom line on each tab. +function FoldingBook:draw() + if not FoldingBook.super.draw(self) then return false end + + for _, pane in ipairs(self.panes) do + local x = pane.tab.position.x + local y = pane.tab.position.y + pane.tab:get_height() + local w = self:get_width() + renderer.draw_rect(x, y, w, 2, style.selection) + end + + return true +end + + +return FoldingBook diff --git a/debian/extra/libraries/widget/fonts/cache.lua b/debian/extra/libraries/widget/fonts/cache.lua new file mode 100644 index 0000000..2dc6471 --- /dev/null +++ b/debian/extra/libraries/widget/fonts/cache.lua @@ -0,0 +1,287 @@ +local core = require "core" +local common = require "core.common" +local Object = require "core.object" +local FontInfo = require "libraries.widget.fonts.info" + +---@class widget.fonts.cache : core.object +---@overload fun():widget.fonts.cache +---@field fontinfo widget.fonts.info +---@field found integer +---@field found_monospaced integer +---@field building boolean +---@field monosppaced boolean +---@field searching_monospaced boolean +---@field fontdirs table +---@field fonts widget.fonts.data[] +local FontCache = Object:extend() + +---Constructor +function FontCache:new() + self.fontinfo = FontInfo() + self.fontdirs = {} + self.fonts = {} + self.loaded_fonts = {} + self.found = 0 + self.found_monospaced = 0 + self.building = false + self.searching_monospaced = false + self.monospaced = false + + table.insert(self.fontdirs, USERDIR .. "/fonts") + table.insert(self.fontdirs, DATADIR .. "/fonts") + + if PLATFORM == "Windows" then + table.insert(self.fontdirs, HOME .. PATHSEP .. "AppData\\Local\\Microsoft\\Windows\\Fonts" ) + table.insert(self.fontdirs, os.getenv("SYSTEMROOT") .. PATHSEP .. "Fonts" ) + elseif PLATFORM == "Mac OS X" then + table.insert(self.fontdirs, HOME .. "/Library/Fonts") + table.insert(self.fontdirs, "/Library/Fonts") + table.insert(self.fontdirs, "/System/Library/Fonts") + else + table.insert(self.fontdirs, HOME .. "/.local/share/fonts") + table.insert(self.fontdirs, HOME .. "/.fonts") + table.insert(self.fontdirs, "/usr/local/share/fonts") + table.insert(self.fontdirs, "/usr/share/fonts") + end + + if not self:load_cache() then + self:build() + elseif not self.monospaced then + self:verify_monospaced() + end +end + +---Check if the cache is already building. +---@return boolean building +function FontCache:is_building() + if self.building or self.searching_monospaced then + return true + end + return false +end + +---Build the font cache and save it. +---@return boolean started False if cache is already been built +function FontCache:build() + if self:is_building() then + core.log_quiet("The font cache is already been generated, please wait.") + return false + end + + self.found = 0 + self.building = true + self.monospaced = false + self.loaded_fonts = {} + + core.log_quiet("Generating font cache...") + local start_time = system.get_time() + + local this = self + core.add_thread(function() + for _, dir in ipairs(this.fontdirs) do + this:scan_dir(dir) + end + this:save_cache() + this.building = false + this.loaded_fonts = {} + core.log_quiet( + "Font cache generated in %.1fs for %s fonts!", + system.get_time() - start_time, tostring(this.found) + ) + self:verify_monospaced() + end) + + return true +end + +---Clear current font cache and rebuild it. +---@return boolean started False if cache is already been built +function FontCache:rebuild() + if self:is_building() then + core.log_quiet("The font cache is already been generated, please wait.") + return false + end + + local fontcache_file = USERDIR .. "/font_cache.lua" + local file = io.open(fontcache_file, "r") + + if file ~= nil then + file:close() + os.remove(fontcache_file) + end + + self.fonts = {} + self.loaded_fonts = {} + self.found = 0 + self.found_monospaced = 0 + + return self:build() +end + +---Scan a directory for valid font files and load them into the cache. +---@param path string +---@param run_count? integer +function FontCache:scan_dir(path, run_count) + run_count = run_count or 1 + local can_yield = coroutine.running() + local list = system.list_dir(path) + if list then + for _, name in pairs(list) do + if name:match("%.[tToO][tT][fFcC]$") and not self.loaded_fonts[name] then + -- prevent loading of duplicate files + self.loaded_fonts[name] = true + local font_path = path .. PATHSEP .. name + local read, errmsg = self.fontinfo:read(font_path) + + if read then + local font_data + font_data, errmsg = self.fontinfo:get_data() + if font_data then + table.insert(self.fonts, font_data) + self.found = self.found + 1 + else + io.stderr:write( + "Error: " .. path .. PATHSEP .. name .. "\n" + .. " " .. errmsg .. "\n" + ) + end + else + io.stderr:write( + "Error: " .. path .. PATHSEP .. name .. "\n" + .. " " .. errmsg .. "\n" + ) + end + if can_yield and run_count % 100 == 0 then + coroutine.yield() + end + else + self:scan_dir(path .. PATHSEP .. name, run_count) + end + run_count = run_count + 1 + end + end +end + +---Search and mark monospaced fonts on currently loaded cache and save it. +function FontCache:verify_monospaced() + if self:is_building() then + core.log_quiet("The monospaced verification is already running, please wait.") + return + end + + self.found_monospaced = 0 + self.searching_monospaced = true + self.monospaced = false + + core.log_quiet("Finding monospaced fonts...") + local start_time = system.get_time() + + local this = self + core.add_thread(function() + for _, font in ipairs(this.fonts) do + if not font.monospace then + FontInfo.check_is_monospace(font) + end + if font.monospace then + this.found_monospaced = this.found_monospaced + 1 + end + coroutine.yield() + end + this.monospaced = true + this:save_cache() + this.searching_monospaced = false + core.log_quiet( + "Found %s monospaced fonts in %.1fs!", + tostring(this.found_monospaced), system.get_time() - start_time + ) + end) +end + +---Load font cache from persistent file for faster startup time. +function FontCache:load_cache() + local ok, t = pcall(dofile, USERDIR .. "/font_cache.lua") + if ok then + self.fonts = t.fonts + self.monospaced = t.monospaced + self.found = t.found + self.found_monospaced = t.found_monospaced + return true + end + return false +end + +---Store current font cache to persistent file. +function FontCache:save_cache() + local fp = io.open(USERDIR .. "/font_cache.lua", "w") + if fp then + local output = "{\n" + .. "found = "..tostring(self.found)..",\n" + .. "found_monospaced = "..tostring(self.found_monospaced)..",\n" + .. "monospaced = "..tostring(self.monospaced)..",\n" + .. "[\"fonts\"] = " + .. common.serialize( + self.fonts, + { pretty = true, escape = true, sort = true, initial_indent = 1 } + ):gsub("^%s+", "") + .. "\n}\n" + fp:write("return ", output) + fp:close() + end +end + +---Search for a font and return the best match. +---@param name string +---@param style? widget.fonts.style +---@param monospaced? boolean +---@return widget.fonts.data? font_data +---@return string? errmsg +function FontCache:search(name, style, monospaced) + if #self.fonts == 0 then + return nil, "the font cache needs to be rebuilt" + end + + style = style or "regular" + name = name:ulower() + style = style:ulower() + + if name == "monospace" then + name = "mono" + monospaced = true + end + + if not self.monospaced then monospaced = false end + + ---@type widget.fonts.data + local fontdata = nil + local prev_score = 0 + + for _, font in ipairs(self.fonts) do + if not monospaced or (monospaced and font.monospace) then + local score = system.fuzzy_match( + font.fullname:ulower(), + name .. " " .. style, + false + ) + if score ~= nil and (score > prev_score or prev_score == 0) then + fontdata = font + prev_score = score + end + end + end + + if fontdata then + local fontfile = io.open(fontdata.path, "r") + if not fontfile then + return nil, "found font file does not exists, cache is outdated" + else + fontfile:close() + end + else + return nil, "no matching font found" + end + + return fontdata +end + + +return FontCache diff --git a/debian/extra/libraries/widget/fonts/info.lua b/debian/extra/libraries/widget/fonts/info.lua new file mode 100644 index 0000000..3ffa696 --- /dev/null +++ b/debian/extra/libraries/widget/fonts/info.lua @@ -0,0 +1,550 @@ +-- Based on the code from: +-- https://gist.github.com/zr-tex8r/1969061a025fa4fc5486c9c28460f48e + +local Object = require "core.object" + +-------------------------------------------------------------------------------- +-- Class Declarations +-------------------------------------------------------------------------------- + +---@class widget.fonts.cdata : core.object +---@overload fun(data:string):widget.fonts.cdata +---@field private data string +---@field private position integer +local FontCDATA = Object:extend() + +---@class widget.fonts.reader : core.object +---@overload fun(font_path?:string):widget.fonts.reader +---@field private file file* +---@field private path string +local FontReader = Object:extend() + +---@class widget.fonts.data +---@field public path string +---@field public id number @Numerical id of the font +---@field public type '"ttc"' | '"ttf"' | '"otf"' +---@field public copyright string +---@field public family string +---@field public subfamily '"Regular"' | '"Bold"' | '"Italic"' | '"Bold Italic"' +---@field public fullname string +---@field public version string +---@field public psname string +---@field public url string +---@field public license string +---@field public tfamily string +---@field public tsubfamily '"Regular"' | '"Bold"' | '"Italic"' | '"Bold Italic"' +---@field public wwsfamily string +---@field public wwssubfamily string +---@field public monospace boolean + +---@class widget.fonts.info : core.object +---@overload fun(font_path?:string):widget.fonts.info +---@field private reader widget.fonts.reader +---@field public path string @Path of the font file +---@field public data widget.fonts.data[] @Holds the metadata for each of the embedded fonts +local FontInfo = Object:extend() + +---@alias widget.fonts.style +---|>'"regular"' +---| '"bold"' +---| '"italic"' +---| '"bold italic"' +---| '"thin"' +---| '"medium"' +---| '"light"' +---| '"black"' +---| '"condensed"' +---| '"oblique"' +---| '"bold oblique"' +---| '"extra nold"' +---| '"Extra bold italic"' +---| '"bold condensed"' + +-------------------------------------------------------------------------------- +-- FontCDATA Implementation +-------------------------------------------------------------------------------- +function FontCDATA:new(data) + self.data = data + self.position = 0 +end + +function FontCDATA:__tostring() + return "cdata(pos="..self.position..")" +end + +function FontCDATA:pos(p) + if not p then return self.position end + self.position = p + return self +end + +function FontCDATA:unum(b) + local v, data = 0, self.data + assert(#data >= self.position + b, 11) + for _ = 1, b do + self.position = self.position + 1 + v = v * 256 + data:byte(self.position) + end + return v +end + +function FontCDATA:setunum(b, v) + local t, data = {}, self.data + t[1] = data:sub(1, self.position) + self.position = self.position + b + assert(#data >= self.position, 12) + t[b + 2] = data:sub(self.position + 1) + for i = 1, b do + t[b + 2 - i] = string.char(v % 256) + v = math.floor(v / 256) + end + self.data = table.concat(t, '') + return self +end + +function FontCDATA:str(b) + local data = self.data + self.position = self.position + b + assert(#data >= self.position, 13) + return data:sub(self.position - b + 1, self.position) +end + +function FontCDATA:setstr(s) + local t, data = {}, self.data + t[1], t[2] = data:sub(1, self.position), s + self.position = self.position + #s + assert(#data >= self.position, 14) + t[3] = data:sub(self.position + 1) + self.data = table.concat(t, '') + return self +end + +function FontCDATA:ushort() + return self:unum(2) +end + +function FontCDATA:ulong() + return self:unum(4) +end + +function FontCDATA:setulong(v) + return self:setunum(4, v) +end + +function FontCDATA:ulongs(num) + local t = {} + for i = 1, num do + t[i] = self:unum(4) + end + return t +end + +-------------------------------------------------------------------------------- +-- FontReader Implementation +-------------------------------------------------------------------------------- +function FontReader:new(font_path) + local file, errmsg = io.open(font_path, "rb") + assert(file, errmsg) + self.file = file + self.path = font_path +end + +function FontReader:__gc() + if self.file then + self.file:close() + end +end + +function FontReader:__tostring() + return "reader("..self.path..")" +end + +---@param offset integer +---@param len integer +---@return widget.fonts.cdata? +---@return string|nil errmsg +function FontReader:cdata(offset, len) + local data, errmsg = self:read(offset, len) + if data then + return FontCDATA(data) + end + return nil, errmsg +end + +function FontReader:read(offset, len) + self.file:seek("set", offset) + local data = self.file:read(len) + if data:len() ~= len then + return nil, "failed reading font data" + end + return data +end + +function FontReader:close() + self.file:close() + self.file = nil +end + +-------------------------------------------------------------------------------- +-- FontInfo Helper Functions +-------------------------------------------------------------------------------- +-- speeds up function lookups +local floor, ceil = math.floor, math.ceil + +local function div(x, y) + return floor(x / y), x % y +end + +local function utf16betoutf8(src) + local s, d = { tostring(src):byte(1, -1) }, {} + for i = 1, #s - 1, 2 do + local c = s[i] * 256 + s[i+1] + if c < 0x80 then d[#d+1] = c + elseif c < 0x800 then + local x, y = div(c, 0x40) + d[#d+1] = x + 0xC0; d[#d+1] = y + 0x80 + elseif c < 0x10000 then + local x, y, z = div(c, 0x1000); y, z = div(y, 0x40) + d[#d+1] = x + 0xE0; d[#d+1] = y + 0x80; d[#d+1] = z + 0x80 + else + assert(nil) + end + end + return string.char(table.unpack(d)) +end + +local file_type = { + [0x74746366] = 'ttc', + [0x10000] = 'ttf', + [0x4F54544F] = 'otf', + [1008813135] = 'ttc' +} + +---@param reader widget.fonts.reader +local function otf_offset(reader) + local cd, errmsg = reader:cdata(0, 12) + if not cd then + return nil, errmsg + end + local tag = cd:ulong() + local ftype = file_type[tag]; + if ftype == 'ttc' then + local ver = cd:ulong(); + local num = cd:ulong(); + cd, errmsg = reader:cdata(12, 4 * num) + if not cd then + return nil, errmsg + end + local res = cd:ulongs(num); + return res + elseif ftype == 'otf' or ftype == 'ttf' then + return { 0 } + else + return nil, string.format("unknown file tag: %s", tag) + end +end + +---@param reader widget.fonts.reader +---@param fofs integer +---@param ntbl integer +local function otf_name_table(reader, fofs, ntbl) + local cd_d = reader:cdata(fofs + 12, 16 * ntbl) + if not cd_d then + return nil, "error reading names table" + end + for _ = 1, ntbl do + local t = {-- tag, csum, ofs, len + cd_d:str(4), cd_d:ulong(), cd_d:ulong(), cd_d:ulong() + } + if t[1] == 'name' then + return reader:cdata(t[3], ceil(t[4] / 4) * 4) + end + end + return nil, "name table is missing" +end + +---@param cdata widget.fonts.cdata +local function otf_name_records(cdata) + local nfmt, nnum, nofs = cdata:ushort(), cdata:ushort(), cdata:ushort() + assert(nfmt == 0, string.format("unsupported name table format: %s", nfmt)) + local nr = {} + for i = 1, nnum do + nr[i] = { -- pid, eid, langid, nameid, len, ofs + cdata:ushort(), cdata:ushort(), cdata:ushort(), + cdata:ushort(), cdata:ushort(), cdata:ushort() + nofs + } + end + return nr +end + +---@param cdata widget.fonts.cdata +local function otf_name(cdata, nr, nameid) + local function seek(pid, eid, lid) + for i = 1, #nr do + local t = nr[i] + local ok = (t[4] == nameid and t[1] == pid and t[2] == eid and + t[3] == lid) + if ok then return t end + end + end + + local rec = seek(3, 1, 0x409) + or seek(3, 10, 0x409) + or seek(1, 0, 0) or seek(0, 3, 0) + or seek(0, 4, 0) or seek(0, 6, 0) + + if not rec then return '' end + local s = cdata:pos(rec[6]):str(rec[5]) + return (rec[1] == 3) and utf16betoutf8(s) or s +end + +---@param reader widget.fonts.reader +local function otf_list(reader, fid, fofs) + local cd_fh, errmsg = reader:cdata(fofs, 12) + if not cd_fh then + return nil, errmsg + end + + local tag = cd_fh:ulong() + local ntbl = cd_fh:ushort() + + local cd_n = nil + cd_n, errmsg = otf_name_table(reader, fofs, ntbl) + if not cd_n then + return nil, errmsg + end + + local ext = { id = fid; type = file_type[tag] or '' } + + local nr = nil + nr, errmsg = otf_name_records(cd_n) + if not nr then + return nil, errmsg + end + + local output = { + id = ext.id, + type = ext.type, + copyright = otf_name(cd_n, nr, 0), + family = otf_name(cd_n, nr, 1), + subfamily = otf_name(cd_n, nr, 2), + fullname = otf_name(cd_n, nr, 4), + version = otf_name(cd_n, nr, 5), + psname = otf_name(cd_n, nr, 6), + url = otf_name(cd_n, nr, 11), + license = otf_name(cd_n, nr, 13), + tfamily = otf_name(cd_n, nr, 16), + tsubfamily = otf_name(cd_n, nr, 17), + } + + return output +end + +-------------------------------------------------------------------------------- +-- FontInfo Implementation +-------------------------------------------------------------------------------- + +---Helper function to check and update a font monospace attribute. +---@param font_data widget.fonts.data +---@return boolean checked +---@return string? errmsg +function FontInfo.check_is_monospace(font_data) + if font_data then + local loaded, fontren = pcall(renderer.font.load, font_data.path, 8, {}) + if not loaded then + return false, "could not load font" + else + if fontren:get_width("|") == fontren:get_width("W") then + font_data.monospace = true + else + font_data.monospace = false + end + end + end + return true +end + +---Constructor +---@param font_path? string +function FontInfo:new(font_path) + if type(font_path) == "string" then + self:read(font_path) + else + self.data = {} + self.path = "" + self.last_error = "no font given" + end +end + +local function fontinfo_read_native(self, font_path) + ---@type widget.fonts.data + local font + ---@type string? + local errmsg + + ---@diagnostic disable-next-line + font, errmsg = renderer.font.get_metadata(font_path) + + if not font then + self.last_error = errmsg + return font, errmsg + end + + local add = true + local family = nil + if font.tfamily then + family = font.tfamily + elseif font.family then + family = font.family + end + + local subfamily = nil + if font.tsubfamily then + subfamily = font.tsubfamily -- sometimes tsubfamily includes more styles + elseif font.subfamily then + subfamily = font.subfamily + end + + -- fix font meta data or discard if empty + if family and subfamily then + font.fullname = family .. " " .. subfamily + elseif font.fullname and family and not font.fullname:ufind(family, 1, true) then + font.fullname = font.fullname .. " " .. family + elseif not font.fullname and family then + font.fullname = family + else + self.last_error = "font metadata is empty" + add = false + end + + if add then + table.insert(self.data, font) + else + return nil, self.last_error + end + + return true +end + +local function fontinfo_read_nonnative(self, font_path) + self.reader = FontReader(font_path) + + local tofs, errmsg = otf_offset(self.reader) + + if not tofs then + self.last_error = errmsg + return nil, errmsg + end + + local data = nil + for i = 1, #tofs do + data, errmsg = otf_list(self.reader, i - 1, tofs[i]) + if data then + table.insert(self.data, data) + else + self.last_error = errmsg + return nil, errmsg + end + end + + if self.data[1] then + local font = self.data[1] + + local family = nil + if font.tfamily ~= "" then + family = font.tfamily + elseif font.family ~= "" then + family = font.family + end + + local subfamily = nil + if font.tsubfamily ~= "" then + subfamily = font.tsubfamily -- sometimes tsubfamily includes more styles + elseif font.subfamily ~= "" then + subfamily = font.subfamily + end + + -- fix font meta data or discard if empty + if family and subfamily then + font.fullname = family .. " " .. subfamily + elseif font.fullname ~= "" and family and not font.fullname:ufind(family, 1, true) then + font.fullname = font.fullname .. " " .. family + elseif font.fullname == "" and family then + font.fullname = family + else + self.data = {} + self.last_error = "font metadata is empty" + return nil, self.last_error + end + end + + self.reader:close() + + return true +end + +---Open a font file and read its metadata. +---@param font_path string +---@return widget.fonts.info? +---@return string|nil errmsg +function FontInfo:read(font_path) + self.data = {} + self.path = font_path + + local read, errmsg + + ---@diagnostic disable-next-line + if type(renderer.font.get_metadata) == "function" then + read, errmsg = fontinfo_read_native(self, font_path) + else + read, errmsg = fontinfo_read_nonnative(self, font_path) + end + + if not read then + return read, errmsg + end + + return self +end + +---Get the amount of collections on the font file. +---@return integer +function FontInfo:embedded_fonts_count() + return #self.data +end + +---Get the metadata of a previously read font file without +---copyright and license information which can be long. +---@param idx? integer Optional position of the embedded font +---@return widget.fonts.data? +---@return string|nil errmsg +function FontInfo:get_data(idx) + idx = idx or 1 + local data = {} + + if #self.data > 0 and self.data[idx] then + data = self.data[idx] + else + return nil, self.last_error + end + + return { + path = self.path, + id = data.id, + type = data.type, + family = data.family, + subfamily = data.subfamily, + fullname = data.fullname, + version = data.version, + psname = data.psname, + url = data.url, + tfamily = data.tfamily, + tsubfamily = data.tsubfamily, + wwsfamily = data.wwsfamily, + wwssubfamily = data.wwssubfamily, + monospace = data.monospace or false + } +end + + +return FontInfo diff --git a/debian/extra/libraries/widget/fonts/init.lua b/debian/extra/libraries/widget/fonts/init.lua new file mode 100644 index 0000000..5b3c51f --- /dev/null +++ b/debian/extra/libraries/widget/fonts/init.lua @@ -0,0 +1,230 @@ +local core = require "core" +local common = require "core.common" +local style = require "core.style" +local FontCache = require "libraries.widget.fonts.cache" +local StatusView = require "core.statusview" + +---@class widget.fonts +local Fonts = {} + +---@type widget.fonts.cache | nil +local fontcache = nil + +---@type table | nil +local fonts = nil + +---Last time the status view item was rendered +local last_statusview_render = 0 + +---The amount of fonts matching the user query +local matching_fonts = 0 + +---Flag that indicates if command view font picker is for monospaced +local pick_monospaced = false + +---Generate the list of fonts displayed on the CommandView. +---@param monospaced? boolean Only display fonts detected as monospaced. +local function generate_fonts(monospaced) + if fontcache then + if fontcache.building then monospaced = false end + fonts = {} + for idx, f in ipairs(fontcache.fonts) do + if not monospaced or (monospaced and f.monospace) then + table.insert(fonts, f.fullname .. "||" .. idx) + end + end + end +end + +---Helper function to split a string by a given delimeter. +local function split(s, delimeter, delimeter_pattern) + if not delimeter_pattern then + delimeter_pattern = delimeter + end + + local result = {}; + for match in (s..delimeter):gmatch("(.-)"..delimeter_pattern) do + table.insert(result, match); + end + return result; +end + +local already_cleaning = false + +---Clean the generated font cache used on command view to free some ram +local function clean_fonts_cache() + if not fontcache or already_cleaning then return end + if not fontcache.building and not fontcache.searching_monospaced then + fontcache = nil + fonts = nil + collectgarbage "collect" + else + already_cleaning = true + core.add_thread(function() + while fontcache.building or fontcache.searching_monospaced do + coroutine.yield(1) + end + if + core.active_view ~= core.command_view + or + ( + core.command_view.label ~= "Select Font: " + and + core.command_view.label ~= "List only monospaced fonts?: " + ) + then + fontcache = nil + fonts = nil + collectgarbage "collect" + already_cleaning = false + end + end) + end +end + +---Launch the commandview and let the user select a font. +---@param callback fun(name:string, path:string) +---@param monospaced boolean +function Fonts.show_picker(callback, monospaced) + if not fontcache then fontcache = FontCache() end + + pick_monospaced = monospaced + + if not fontcache.building and (not monospaced or fontcache.monospaced) then + generate_fonts(monospaced) + else + core.add_thread(function() + while + (fontcache.building or (monospaced and not fontcache.monospaced)) + and + core.active_view == core.command_view + and + core.command_view.label == "Select Font: " + do + core.command_view:update_suggestions() + coroutine.yield(2) + end + generate_fonts(monospaced) + core.command_view:update_suggestions() + end) + end + + last_statusview_render = system.get_time() + + core.command_view:enter("Select Font", { + submit = function(text, item) + callback(item.text, item.info) + clean_fonts_cache() + end, + suggest = function(text) + if fontcache.building or (monospaced and fontcache.searching_monospaced) then + generate_fonts(monospaced) + end + local res = common.fuzzy_match(fonts, text) + matching_fonts = #res + for i, name in ipairs(res) do + local font_info = split(name, "||") + local id = tonumber(font_info[2]) + local font_data = fontcache.fonts[id] + res[i] = { + text = font_data.fullname, + info = font_data.path, + id = id + } + end + return res + end, + cancel = function() + clean_fonts_cache() + end + }) +end + +---Same as `show_picker()` but asks the user if he wants a monospaced font. +---@param callback fun(name:string, path:string) +function Fonts.show_picker_ask_monospace(callback) + if not fontcache then fontcache = FontCache() end + + core.command_view:enter("List only monospaced fonts?", { + submit = function(text, item) + Fonts.show_picker(callback, item.mono) + end, + suggest = function(text) + local res = common.fuzzy_match({"Yes", "No"}, text) + for i, name in ipairs(res) do + res[i] = { + text = name, + mono = text == "Yes" and true or false + } + end + return res + end, + cancel = function() + clean_fonts_cache() + end + }) +end + +---Check if the font cache is been built. +---@return boolean building +function Fonts.cache_is_building() + if not fontcache then return false end + return fontcache:is_building() +end + +---Remove current fonts cache file and regenerates a fresh one. +---@return boolean started False if cache is already been built +function Fonts.clean_cache() + if not fontcache then fontcache = FontCache() end + return fontcache:rebuild() +end + +core.status_view:add_item({ + predicate = function() + return core.active_view == core.command_view + and core.command_view.label == "Select Font: " + end, + name = "widget:font-select", + alignment = StatusView.Item.LEFT, + get_item = function() + local found = 0 + local dots, status = "", "" + if fontcache then + if fontcache.building or fontcache.searching_monospaced then + dots = "." + if system.get_time() - last_statusview_render >= 3 then + last_statusview_render = system.get_time() + elseif system.get_time() - last_statusview_render >= 2 then + dots = "..." + elseif system.get_time() - last_statusview_render >= 1 then + dots = ".." + end + end + if fontcache.building then + status = " | searching system fonts" .. dots + elseif fontcache.searching_monospaced then + status = " | detecting monospaced fonts" .. dots + end + + if fontcache.building or not pick_monospaced then + found = fontcache.found + else + found = fontcache.found_monospaced + end + end + + return { + style.text, + style.font, + "Matches: " + .. tostring(matching_fonts) + .. " / " + .. tostring(found) + .. status + } + end, + position = 1 +}) + + +return Fonts diff --git a/debian/extra/libraries/widget/fontslist.lua b/debian/extra/libraries/widget/fontslist.lua new file mode 100644 index 0000000..b2109a0 --- /dev/null +++ b/debian/extra/libraries/widget/fontslist.lua @@ -0,0 +1,223 @@ +-- +-- FontsList Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- +local style = require "core.style" +local Widget = require "libraries.widget" +local Button = require "libraries.widget.button" +local ListBox = require "libraries.widget.listbox" +local FontDialog = require "libraries.widget.fontdialog" +local MessageBox = require "libraries.widget.messagebox" + +---@class widget.fontslist.font : widget +---@field name string +---@field path string + +---@class widget.fontslist : widget +---@overload fun(parent?:widget):widget.fontslist +---@field list widget.listbox +---@field add widget.button +---@field remove widget.button +---@field up widget.button +---@field down widget.button +---@field options renderer.fontoptions +---@field private dialog boolean +local FontsList = Widget:extend() + +---Constructor +---@param parent widget +function FontsList:new(parent) + FontsList.super.new(self, parent) + + self.type_name = "widget.fontslist" + + self.border.width = 0 + + self.dialog = false + + self.options = {} + + self.list = ListBox(self) + + local this = self + + function self.list:on_mouse_pressed(button, x, y, clicks) + if not ListBox.on_mouse_pressed(self, button, x, y, clicks) then + return false + end + + if clicks == 2 and not this.dialog then + this.dialog = true + local selected = this.list:get_selected() + local fontdata = this.list:get_row_data(selected) + ---@type widget.inputdialog + local font = FontDialog(fontdata, this:get_options()) + function font:on_save(fontdata, options) + this:set_options(options) + this:edit_font(selected, fontdata) + end + function font:on_close() + FontDialog.on_close(self) + self:destroy() + this.dialog = false + end + font:show() + end + + return true + end + + self.add = Button(self, "Add") + self.add:set_icon("B") + function self.add:on_click() + if #this.list.rows > 9 then + MessageBox.error("Max Fonts Reached", "Only a maximum of ten fonts can be added.") + return + end + if not this.dialog then + this.dialog = true + ---@type widget.inputdialog + local font = FontDialog(nil, this:get_options()) + function font:on_save(fontdata, options) + this:set_options(options) + this:add_font(fontdata) + end + function font:on_close() + FontDialog.on_close(self) + self:destroy() + this.dialog = false + end + font:show() + end + end + + self.remove = Button(self, "Remove") + self.remove:set_icon("C") + function self.remove:on_click() + local selected = this.list:get_selected() + if selected then + if #this.list.rows > 1 then + this:remove_font(selected) + else + MessageBox.error("Font required", "A minimum of one font is needed") + end + else + MessageBox.error("No font selected", "Please select a font to remove") + end + end + + self.up = Button(self, "") + self.up:set_icon("<") + self.up:set_tooltip("increase font priority") + function self.up:on_click() + local selected = this.list:get_selected() + if selected then + this.list:move_row_up(selected) + this:on_change() + else + MessageBox.error("No font selected", "Please select a font to move") + end + end + + self.down = Button(self, "") + self.down:set_icon(">") + self.down:set_tooltip("decrease font priority") + function self.down:on_click() + local selected = this.list:get_selected() + if selected then + this.list:move_row_down(selected) + this:on_change() + else + MessageBox.error("No font selected", "Please select a font to move") + end + end +end + +---Add a new font into the list. +---@param font widget.fontslist.font +function FontsList:add_font(font) + self.list:add_row({font.name}, font) + self.list:set_visible_rows() + self:on_change() +end + +---Edit an existing font on the list. +---@param idx integer +---@param font widget.fontslist.font +function FontsList:edit_font(idx, font) + self.list:set_row(idx, {font.name}) + self.list:set_row_data(idx, font) + self:on_change() +end + +---Remove the given font from the list. +---@param idx integer +function FontsList:remove_font(idx) + self.list:remove_row(idx) + self:on_change() +end + +---Return the fonts from the list. +---@return table +function FontsList:get_fonts() + local output = {} + local count = #self.list.rows + for i=1, count, 1 do + table.insert(output, self.list:get_row_data(i)) + end + return output +end + +---Set the global options for the fonts group +---@param options renderer.fontoptions +function FontsList:set_options(options) + self.options = options +end + +---Get the global options for the font group +---@return renderer.fontoptions +function FontsList:get_options() + return self.options +end + +function FontsList:update() + if not FontsList.super.update(self) then return false end + + if self.size.x == 0 then + self.size.x = self.add:get_width() + + (style.padding.x / 2) + self.remove:get_width() + + (style.padding.x / 2) + self.up:get_width() + + (style.padding.x / 2) + self.down:get_width() + (50 * SCALE) + self.size.y = self.add:get_height() + (style.padding.y * 2) + 100 + end + + self.list:set_position(0, 0) + + self.list:set_size( + self.size.x, + self.size.y - self.add:get_height() - (style.padding.y * 2) + ) + + self.add:set_position(0, self.list:get_bottom() + style.padding.y) + + self.remove:set_position( + self.add:get_right() + (style.padding.x / 2), + self.list:get_bottom() + style.padding.y + ) + + self.up:set_position( + self.remove:get_right() + (style.padding.x / 2), + self.list:get_bottom() + style.padding.y + ) + + self.down:set_position( + self.up:get_right() + (style.padding.x / 2), + self.list:get_bottom() + style.padding.y + ) + + return true +end + + +return FontsList diff --git a/debian/extra/libraries/widget/init.lua b/debian/extra/libraries/widget/init.lua new file mode 100644 index 0000000..c25352f --- /dev/null +++ b/debian/extra/libraries/widget/init.lua @@ -0,0 +1,1544 @@ +-- +-- Base widget implementation for lite. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local core = require "core" +local config = require "core.config" +local style = require "core.style" +local keymap = require "core.keymap" +local View = require "core.view" +local ScrollBar = require "libraries.widget.scrollbar" +local RootView + +---Represents the border of a widget. +---@class widget.border +---@field public width number +---@field public color renderer.color | nil + +---Represents the position of a widget. +---@class widget.position +---@field public x number Real X +---@field public y number Real y +---@field public rx number Relative X +---@field public ry number Relative Y +---@field public dx number Dragging initial x position +---@field public dy number Dragging initial y position + +---@class widget.animation.options +---Prevents duplicated animations from getting added. +---@field name? string +---Speed of the animation, defaults to 0.5 +---@field rate? number +---Called each time the value of a property changes. +---@field on_step? fun(target:table, property:string, value:number) +---Called when the animation finishes. +---@field on_complete? fun(widget:widget) + +---@class widget.animation +---@field target table +---@field properties table +---@field options? widget.animation.options + +---Represents a reference to a font stored elsewhere. +---@class widget.fontreference +---@field public container table +---@field public name string + +---@alias widget.font widget.fontreference | renderer.font | string + +---@alias widget.clicktype +---| "left" +---| "right" + +---@alias widget.styledtext table + +---A base widget +---@class widget : core.view +---@overload fun(parent?:widget, floating?:boolean):widget +---@field public super widget +---@field public parent widget | nil +---@field public name string +---@field public position widget.position +---Modifying this property directly is not advised, use set_size() instead. +---@field public size widget.position +---@field public childs table +---@field public child_active widget | nil +---@field public zindex integer +---@field public border widget.border +---@field public clickable boolean +---@field public draggable boolean +---@field public scrollable boolean +---@field public font widget.font +---@field public foreground_color renderer.color +---@field public background_color renderer.color +---@field public render_background boolean +---@field public type_name string +---@field protected visible boolean +---@field protected has_focus boolean +---@field protected dragged boolean +---@field protected tooltip string +---@field protected label string | widget.styledtext +---@field protected input_text boolean +---@field protected textview widget +---@field protected next_zindex integer +---@field protected mouse widget.position +---@field protected prev_size widget.position +---@field protected mouse_is_pressed boolean +---@field protected mouse_is_hovering boolean +---@field protected mouse_pressed_outside boolean +---@field protected is_scrolling boolean +---By default is set to true to allow ctrl+wheel or cmd+wheel on mac to scale +---the interface, you can set it to false on your parent widget to allow +---manually intercepting ctrl+wheel. +---@field protected skip_scroll_ctrl boolean +---@field protected captured_widget widget Widget that captured mouse events +---@field protected animations widget.animation[] +local Widget = View:extend() + +---Indicates on a widget.styledtext that a new line follows. +---@type integer +Widget.NEWLINE = 1 + +---Keep track of last hovered widget to properly trigger on_mouse_leave +---@type widget | nil +local last_hovered_child = nil + +---A list of floating widgets that need to receive events. +---@type table +local floating_widgets = {} + +---Flag that indicates if the tooltip is been shown +---@type boolean +local widget_showing_tooltip = false + +---When no parent is given to the widget constructor it will automatically +---overwrite RootView methods to intercept system events. +---@param parent? widget +---@param floating? boolean +function Widget:new(parent, floating) + Widget.super.new(self) + + self.v_scrollbar = ScrollBar(self, {direction = "v", alignment = "e"}) + self.h_scrollbar = ScrollBar(self, {direction = "h", alignment = "e"}) + + self.type_name = "widget" + self.parent = parent + self.name = "---" -- defaults to the application name + if type(floating) == "boolean" then + self.defer_draw = floating + else + self.defer_draw = true + end + self.childs = {} + self.child_active = nil + self.zindex = nil + self.next_zindex = 1 + self.border = { + width = 1, + color = nil + } + self.foreground_color = nil + self.background_color = nil + self.render_background = true + self.visible = parent and true or false + self.has_focus = false + self.clickable = true + self.draggable = false + self.dragged = false + self.font = "font" + self.force_events = {} + self.tooltip = "" + self.label = "" + self.input_text = false + self.textview = nil + self.mouse = {x = 0, y = 0} + self.prev_size = {x = 0, y = 0} + self.is_scrolling = false + self.skip_scroll_ctrl = true + + self.mouse_is_pressed = false + self.mouse_is_hovering = false + + -- used to allow proper node resizing + self.mouse_pressed_outside = false + + self.animations = {} + + if parent then + parent:add_child(self) + elseif self.defer_draw then + table.insert(floating_widgets, self) + Widget.override_rootview() + end + + self:set_position(0, 0) +end + +---Useful for debugging. +function Widget:__tostring() + return self.type_name +end + +---Add a child widget, automatically assign a zindex if non set and sorts +---them in reverse order for better events matching. +---@param child widget +function Widget:add_child(child) + if not child.zindex then + child.zindex = self.next_zindex + self.next_zindex = self.next_zindex + 1 + end + + table.insert(self.childs, child) + table.sort(self.childs, function(t1, t2) return t1.zindex > t2.zindex end) +end + +---Remove a child widget. +---@param child widget +function Widget:remove_child(child) + for position, element in ipairs(self.childs) do + if child == element then + child:destroy_childs() + table.remove(self.childs, position) + break + end + end +end + +---Show the widget. +function Widget:show() + if not self.parent then + if self.size.x <= 0 or self.size.y <= 0 then + self.size.x = self.prev_size.x + self.size.y = self.prev_size.y + end + self.prev_size.x = 0 + self.prev_size.y = 0 + end + self.visible = true + -- re-triggers update to make sure everything was properly calculated + -- and redraw the interface once, maybe something else can be changed + -- to not require this action, but for now lets do this. + core.add_thread(function() + self:update() + core.redraw = true + end) +end + +---Perform an animated show. +---@param lock_x? boolean Do not resize width while animating +---@param lock_y? boolean Do not resize height while animating +---@param options? widget.animation.options +function Widget:show_animated(lock_x, lock_y, options) + if not self.parent then + if self.size.x <= 0 or self.size.y <= 0 then + self.size.x = self.prev_size.x + self.size.y = self.prev_size.y + end + self.prev_size.x = 0 + self.prev_size.y = 0 + end + + local target_x, target_y = math.floor(self.size.x), math.floor(self.size.y) + self.size.x = lock_x and target_x or 0 + self.size.y = lock_y and target_y or 0 + local properties = {} + if not lock_x then properties["x"] = target_x end + if not lock_y then properties["y"] = target_y end + options = options or {} + self:animate(self.size, properties, { + name = options.name or "show_animated", + rate = options.rate, + on_step = options.on_step, + on_complete = options.on_complete + }) + + self.visible = true +end + +---Hide the widget. +function Widget:hide() + self.visible = false + -- we need to force size to zero on parent widget to properly hide it + -- when used as a lite node, otherwise the reserved space of the node + -- will stay visible and dragging will reveal empty space. + if not self.parent then + if self.size.x > 0 or self.size.y > 0 then + -- we only do this once to prevent issues of consecutive hide calls + if self.prev_size.x == 0 and self.prev_size.y == 0 then + self.prev_size.x = self.size.x + self.prev_size.y = self.size.y + end + self.size.x = 0 + self.size.y = 0 + end + end +end + +---Perform an animated hide. +---@param lock_x? boolean Do not resize width while animating +---@param lock_y? boolean Do not resize height while animating +---@param options? widget.animation.options +function Widget:hide_animated(lock_x, lock_y, options) + local x, y = self.size.x, self.size.y + local target_x = lock_x and self.size.x or 0 + local target_y = lock_y and self.size.y or 0 + local properties = {} + if not lock_x then properties["x"] = target_x end + if not lock_y then properties["y"] = target_y end + options = options or {} + self:animate(self.size, properties, { + name = options.name or "hide_animated", + rate = options.rate, + on_step = options.on_step, + on_complete = function() + self.size.x, self.size.y = x, y + self:hide() + if options.on_complete then + options.on_complete(self) + end + end + }) +end + +---When set to false the background rendering is disabled. +---@param enable? boolean | nil +function Widget:toggle_background(enable) + if type(enable) == "boolean" then + self.render_background = enable + else + self.render_background = not self.render_background + end +end + +---Toggle visibility of widget. +---@param animated? boolean +---@param lock_x? boolean +---@param lock_y? boolean +---@param options? widget.animation.options +function Widget:toggle_visible(animated, lock_x, lock_y, options) + if not self.visible then + if not animated then + self:show() + else + self:show_animated(lock_x, lock_y, options) + end + else + if not animated then + self:hide() + else + self:hide_animated(lock_x, lock_y, options) + end + end +end + +---Check if the widget is visible also recursing to the parent visibility. +---@return boolean +function Widget:is_visible() + if + not self.visible or (self.parent and not self.parent:is_visible()) + then + return false + end + return true +end + +---Taken from the logview and modified it a tiny bit. +---TODO: something similar should be on lite-xl core. +---@param font widget.font +---@param text string +---@param x integer +---@param y integer +---@param color renderer.color +---@param only_calc boolean +---@return integer resx +---@return integer resy +---@return integer width +---@return integer height +function Widget:draw_text_multiline(font, text, x, y, color, only_calc) + font = self:get_font(font) + local th = font:get_height() + local resx, resy = x, y + local width, height = 0, 0 + for line in (text .. "\n"):gmatch("(.-)\n") do + resy = y + if only_calc then + resx = x + font:get_width(line) + else + resx = renderer.draw_text(font, line, x, y, color) + end + y = y + th + width = math.max(width, resx - x) + height = height + th + end + return resx, resy, width, height +end + +---Render or calculate the size of the specified range of elements +---in a styled text elemet. +---@param text widget.styledtext +---@param start_idx integer +---@param end_idx integer +---@param x integer +---@param y integer +---@param only_calc boolean +---@return integer width +---@return integer height +function Widget:draw_styled_text(text, x, y, only_calc, start_idx, end_idx) + local font = self:get_font() + local color = self.foreground_color or style.text + local width = 0 + local height = font:get_height() + local new_line = false + local nx = x + + start_idx = start_idx or 1 + end_idx = end_idx or #text + + for pos=start_idx, end_idx, 1 do + local element = text[pos] + local ele_type = type(element) + if + ele_type == "userdata" + or + (element.container or type(element[1]) == "userdata") + then + if ele_type == "table" and element.container then + font = element.container[element.name] + else + font = element + end + elseif ele_type == "table" then + color = element + elseif element == Widget.NEWLINE then + y = y + font:get_height() + nx = x + new_line = true + elseif ele_type == "string" then + local rx, ry, w, h = self:draw_text_multiline( + font, element, nx, y, color, only_calc + ) + y = ry + nx = rx + if new_line then + height = height + h + width = math.max(width, w) + new_line = false + else + height = math.max(height, h) + width = width + w + end + end + end + + return width, height +end + +---Draw the widget configured border or custom one. +---@param x? number +---@param y? number +---@param w? number +---@param h? number +function Widget:draw_border(x, y, w, h) + if self.border.width <= 0 then return end + + x = x or self.position.x + y = y or self.position.y + w = w or self.size.x + h = h or self.size.y + + x = x - self.border.width + y = y - self.border.width + w = w + (self.border.width * 2) + h = h + (self.border.width * 2) + + -- Draw lines instead of full rectangle to be able to draw on top + + --top + renderer.draw_rect( + x, y, w + x % 1 - self.border.width, self.border.width, + self.border.color or style.text + ) + --bottom + renderer.draw_rect( + x, y+h - self.border.width, w + x % 1 - self.border.width, self.border.width, + self.border.color or style.text + ) + --right + renderer.draw_rect( + x+w - self.border.width, y, self.border.width, h, + self.border.color or style.text + ) + --left + renderer.draw_rect( + x, y, self.border.width, h, + self.border.color or style.text + ) +end + +---Called by lite node system to properly resize the widget. +---@param axis string | "'x'" | "'y'" +---@param value number +function Widget:set_target_size(axis, value) + if not self.visible then + return false + end + if axis == "x" then + self:set_size(value) + else + self:set_size(nil, value) + end + return true +end + +---@param width? integer +---@param height? integer +function Widget:set_size(width, height) + -- take into consideration the border as part of size + if width then + if width > (self.border.width * 2) then + width = width - (self.border.width * 2) + else + width = 0 + end + end + if height then + if height > (self.border.width * 2) then + height = height - (self.border.width * 2) + else + height = 0 + end + end + + if not self.parent and not self.visible then + if width then self.prev_size.x = width end + if height then self.prev_size.y = height end + else + if width then self.size.x = width end + if height then self.size.y = height end + end +end + +---Set the widget border size and appropriately re-set the widget size. +---@param width integer +function Widget:set_border_width(width) + local wwidth, wheight = 0, 0; + if self.border.width > 0 then + local prev_width = self.border.width * 2 + if not self.parent and not self.visible then + wwidth = self.prev_size.x + prev_width + wheight = self.prev_size.y + prev_width + else + wwidth = self.size.x + prev_width + wheight = self.size.y + prev_width + end + end + self.border.width = width + self:set_size(wwidth, wheight) +end + +---Called on the update function to be able to scroll the child widgets. +function Widget:update_position() + if self.parent then + self.position.x = self.position.rx + self.border.width + self.position.y = self.position.ry + self.border.width + + -- add offset to properly scroll + local ox, oy = self.parent:get_content_offset() + self.position.x = ox + self.position.x + self.position.y = oy + self.position.y + end + + for _, child in pairs(self.childs) do + child:update_position() + end +end + +---Set the position of the widget and updates the child absolute coordinates +---@param x? integer +---@param y? integer +function Widget:set_position(x, y) + if x then self.position.x = x + self.border.width end + if y then self.position.y = y + self.border.width end + + if self.parent then + -- add offset to properly scroll + local ox, oy = self.parent:get_content_offset() + + if x then + self.position.rx = x + self.position.x = ox + self.position.x + end + + if y then + self.position.ry = y + self.position.y = oy + self.position.y + end + end + + if x or y then + for _, child in pairs(self.childs) do + child:set_position(child.position.rx, child.position.ry) + end + end +end + +---Get the real renderer.font associated with a widget.font. +---@param font? widget.font +---@return renderer.font +function Widget:get_font(font) + if not font then font = self.font end + local font_type = type(font) + if font_type == "userdata" then + return font + elseif font_type == "string" then + return style[font] + elseif font and font.container then + return font.container[font.name] + end + if not font then + return style.font + end + return font +end + +---Get the relative position in relation to parent +---@return widget.position +function Widget:get_position() + local position = { x = self.position.x, y = self.position.y } + if self.parent then + position.x = self.position.rx + position.y = self.position.ry + end + return position +end + +---Get width including borders. +---@return number +function Widget:get_width() + return self.size.x + (self.border.width * 2) +end + +---Get height including borders. +---@return number +function Widget:get_height() + return self.size.y + (self.border.width * 2) +end + +---Get the right x coordinate relative to parent +---@return number +function Widget:get_right() + return self:get_position().x + self:get_width() +end + +---Get the bottom y coordinate relative to parent +---@return number +function Widget:get_bottom() + return self:get_position().y + self:get_height() +end + +---Overall height of the widget accounting all visible child widgets. +---@return number +function Widget:get_real_height() + local size = 0 + for _, child in pairs(self.childs) do + if child.visible then + size = math.max(size, child:get_bottom()) + end + end + return size +end + +---Overall width of the widget accounting all visible child widgets. +---@return number +function Widget:get_real_width() + local size = 0 + for _, child in pairs(self.childs) do + if child.visible then + size = math.max(size, child:get_right()) + end + end + return size +end + +---Check if the given mouse coordinate is hovering the widget +---@param x number +---@param y number +---@return boolean +function Widget:mouse_on_top(x, y) + return + self.visible + and + x >= self.position.x - self.border.width + and + x <= self.position.x - self.border.width + self:get_width() + and + y >= self.position.y - self.border.width + and + y <= self.position.y - self.border.width + self:get_height() +end + +---Mark a widget as having focus. +---TODO: Implement set focus system by pressing a key like tab? +function Widget:set_focus(has_focus) + self.set_focus = has_focus +end + +---Text displayed when the widget is hovered. +---@param tooltip string +function Widget:set_tooltip(tooltip) + self.tooltip = tooltip +end + +---A text label for the widget, not all widgets support this. +---@param text string | widget.styledtext +function Widget:set_label(text) + self.label = text +end + +---Used internally when dragging is activated. +---@param x number +---@param y number +function Widget:drag(x, y) + if self.position.dx and self.position.dy then + self:set_position(x - self.position.dx, y - self.position.dy) + end +end + +---Center the widget horizontally and vertically to the screen or parent widget. +function Widget:centered() + local w, h = system.get_window_size(core.window); + if self.parent then + w = self.parent:get_width() + h = self.parent:get_height() + end + self:set_position( + (w / 2) - (self:get_width() / 2), + (h / 2) - (self:get_height() / 2) + ) +end + +---Replaces current active child with a new one and calls the +---activate/deactivate events of the child. This is especially +---used to send text input events to widgets with input_text support. +---@param child? widget If nil deactivates current child +function Widget:swap_active_child(child) + if self.parent then + self.parent:swap_active_child(child) + return + end + + if child and child == self.child_active then return end + + local active_child = self.child_active + + if self.child_active then + self.child_active:deactivate() + end + + self.child_active = child + + if child then + if not self.prev_view then + self.prev_view = core.active_view + end + core.set_active_view(child.input_text and child.textview or child) + self.child_active:activate() + elseif self.prev_view then + -- return focus to previous view + if self.prev_view ~= active_child then + core.set_active_view(self.prev_view) + else + core.set_active_view(self) + end + self.prev_view = nil + end +end + +---Calculates the y scrollable size taking into account the bottom most +---widget or the size of the widget it self if greater. +---@return number +function Widget:get_scrollable_size() + return math.max(self.size.y, self:get_real_height()) +end + +---Calculates the x scrollable size taking into account the right most +---widget or the size of the widget it self if greater. +---@return number +function Widget:get_h_scrollable_size() + return math.max(self.size.x, self:get_real_width()) +end + +---The name that is displayed on lite-xl tabs. +function Widget:get_name() + return self.parent and self.parent:get_name() or self.name +end + +-- +-- Events +-- + +---Send file drop event to hovered child. +---@param filename string +---@param x number +---@param y number +---@return boolean processed +function Widget:on_file_dropped(filename, x, y) + if not self.visible then return false end + + for _, child in pairs(self.childs) do + if child:mouse_on_top(x, y) then + return child:on_file_dropped(filename, x, y) + end + end + + return false +end + +---Redirects any text input to active child with the input_text flag. +---@param text string +---@return boolean processed +function Widget:on_text_input(text) + if not self.visible then return false end + + Widget.super.on_text_input(self, text) + + if self.child_active then + self.child_active:on_text_input(text) + return true + end + + return false +end + +---All mouse events will be directly sent to the widget even if mouse moves +---outside the widget region. +---@param scrolling? boolean Capture for scrolling +function Widget:capture_mouse(scrolling) + local parent = self.parent + while parent do + -- propagate to parents so if mouse is not on top still + -- reach the childrens when the mouse is released + if scrolling then parent.is_scrolling = true end + parent.captured_widget = self + parent = parent.parent + end + if scrolling then self.is_scrolling = true end +end + +---Undo capture_mouse() +function Widget:release_mouse() + local parent = self.parent + while parent do + -- propagate to parents so if mouse is not on top still + -- reach the childrens when the mouse is released + parent.is_scrolling = false + parent.captured_widget = nil + parent = parent.parent + end + self.is_scrolling = false +end + +---Send mouse pressed events to hovered child or starts dragging if enabled. +---@param button widget.clicktype +---@param x number +---@param y number +---@param clicks integer +---@return boolean processed +function Widget:on_mouse_pressed(button, x, y, clicks) + if not self.visible then return false end + + -- Capture when scrollbar is pressed + if Widget.super.on_mouse_pressed(self, button, x, y, clicks) then + self:capture_mouse(true) + return true + end + + for _, child in pairs(self.childs) do + if child:mouse_on_top(x, y) and child.clickable then + child:on_mouse_pressed(button, x, y, clicks) + return true + end + end + + if self:mouse_on_top(x, y) then + self.mouse_is_pressed = true + + if self.parent then + -- propagate to parents so if mouse is not on top still + -- reach the childrens when the mouse is released + self.parent.mouse_is_pressed = true + end + + if self.draggable and not self.child_active then + self.position.dx = x - self.position.x + self.position.dy = y - self.position.y + system.set_cursor("hand") + end + else + self:swap_active_child() + return false + end + + return true +end + +---Send mouse released events to hovered child, ends dragging if enabled and +---emits on click events if applicable. +---@param button widget.clicktype +---@param x number +---@param y number +---@return boolean processed +function Widget:on_mouse_released(button, x, y) + if not self.visible then return false end + + if widget_showing_tooltip then + widget_showing_tooltip = false + core.status_view:remove_tooltip() + end + + if self.captured_widget then + self.captured_widget:on_mouse_released(button, x, y) + if self.is_scrolling then + self.captured_widget:release_mouse() + end + return true + end + + Widget.super.on_mouse_released(self, button, x, y) + + self:swap_active_child() + + if self.child_active then + self.child_active:on_mouse_released(button, x, y) + end + + if not self.dragged then + for _, child in pairs(self.childs) do + local mouse_on_top = child:mouse_on_top(x, y) + if + mouse_on_top + or + child.mouse_is_pressed + then + child:on_mouse_released(button, x, y) + if child.input_text then + self:swap_active_child(child) + end + if mouse_on_top and child.mouse_is_pressed then + child:on_click(button, x, y) + end + return true + end + end + end + + if + not self.dragged + and + not self.mouse_is_pressed + then + return false + end + + if self.mouse_is_pressed then + if self:mouse_on_top(x, y) then + self:on_click(button, x, y) + end + self.mouse_is_pressed = false + if self.parent then + self.parent.mouse_is_pressed = false + end + if self.draggable then + system.set_cursor("arrow") + end + end + + self.dragged = false + + return true +end + +---Event emitted when the value of the widget changes. +---If applicable, child widgets should call this method +---when its value changes. +---@param value any +function Widget:on_change(value) end + +---Click event emitted on a succesful on_mouse_pressed +---and on_mouse_released events combo. +---@param button widget.clicktype +---@param x number +---@param y number +function Widget:on_click(button, x, y) end + +---Emitted to input_text widgets when clicked. +function Widget:activate() end + +---Emitted to input_text widgets on lost focus. +function Widget:deactivate() end + +---Besides the on_mouse_moved this event emits on_mouse_enter +---and on_mouse_leave for easy hover effects. Also, if the +---widget is scrollable and pressed this will drag it unless +---there is an active input_text child active. +---@param x number +---@param y number +---@param dx number +---@param dy number +function Widget:on_mouse_moved(x, y, dx, dy) + if not self.visible then return false end + + if self.captured_widget then + self.captured_widget:on_mouse_moved(x, y, dx, dy) + return true + end + + Widget.super.on_mouse_moved(self, x, y, dx, dy) + + -- store latest mouse coordinates for usage on the on_mouse_wheel event. + self.mouse.x = x + self.mouse.y = y + + if self.child_active then + self.child_active:on_mouse_moved(x, y, dx, dy) + end + + if not self.dragged then + local hovered = nil + for _, child in pairs(self.childs) do + if + not hovered + and + (child:mouse_on_top(x, y) or child.mouse_is_pressed) + then + hovered = child + elseif child.mouse_is_hovering then + if widget_showing_tooltip then + widget_showing_tooltip = false + core.status_view:remove_tooltip() + end + child.mouse_is_hovering = false + child:on_mouse_leave(x, y, dx, dy) + system.set_cursor("arrow") + end + end + + if hovered then + hovered:on_mouse_moved(x, y, dx, dy) + if last_hovered_child and not last_hovered_child:mouse_on_top(x, y) then + last_hovered_child:on_mouse_leave(x, y, dx, dy) + last_hovered_child.mouse_is_hovering = false + last_hovered_child = nil + end + return true; + end + end + + if + not self:mouse_on_top(x, y) + and + not self.mouse_is_pressed + and + not self.mouse_is_hovering + then + return false + end + + local is_over = true + + if self:mouse_on_top(x, y) then + if not self.mouse_is_hovering then + system.set_cursor("arrow") + self.mouse_is_hovering = true + if #self.tooltip > 0 then + widget_showing_tooltip = true + core.status_view:show_tooltip(self.tooltip) + end + self:on_mouse_enter(x, y, dx, dy) + last_hovered_child = self + end + else + self:on_mouse_leave(x, y, dx, dy) + self.mouse_is_hovering = false + is_over = false + end + + if not self.child_active and self.mouse_is_pressed and self.draggable then + system.set_cursor("hand") + self:drag(x, y) + self.dragged = true + return true + end + + return is_over +end + +---Emitted once when the mouse hovers the widget. +function Widget:on_mouse_enter(x, y, dx, dy) + for _, child in pairs(self.childs) do + if child:mouse_on_top(x, y) then + child:on_mouse_enter(x, y, dx, dy) + break + end + end +end + +---Emitted once when the mouse leaves the widget. +function Widget:on_mouse_leave(x, y, dx, dy) + for _, child in pairs(self.childs) do + if child.mouse_is_hovering then + child:on_mouse_leave(x, y, dx, dy) + end + end +end + +function Widget:on_mouse_left() + if not self.captured_widget then + Widget.super.on_mouse_left(self) + self:on_mouse_moved(-1, -1, -1, -1) + end +end + +function Widget:on_mouse_wheel(y, x) + if + not self.visible + or + not self:mouse_on_top(self.mouse.x, self.mouse.y) + then + return false + else + local ctrl_pressed = false + if self.skip_scroll_ctrl and not self.parent then + local ctrl_key = PLATFORM == "Mac OS X" and "cmd" or "ctrl" + ctrl_pressed = keymap.modkeys[ctrl_key] + -- ensure only ctrl/cmd is pressed + if ctrl_pressed then + for key, status in pairs(keymap.modkeys) do + if key ~= ctrl_key and status then + ctrl_pressed = false + break + end + end + end + end + if ctrl_pressed then return false end + end + + for _, child in pairs(self.childs) do + if child:mouse_on_top(self.mouse.x, self.mouse.y) then + if child:on_mouse_wheel(y, x) then + return true + end + end + end + + if self.scrollable then + if keymap.modkeys["shift"] then + x = y + y = 0 + end + if y and y ~= 0 then + self.scroll.to.y = self.scroll.to.y + y * -config.mouse_wheel_scroll + end + if x and x ~= 0 then + self.scroll.to.x = self.scroll.to.x + x * -config.mouse_wheel_scroll + end + return true + end + + return false +end + +---Can be overriden by widgets to listen for scale change events to apply +---any neccesary changes in sizes, padding, etc... +---@param new_scale number +---@param prev_scale number +function Widget:on_scale_change(new_scale, prev_scale) + local font_type = type(self.font) + if + font_type == "userdata" + or + (font_type == "table" and not self.font.container) + then + self.font:set_size( + self.font:get_size() * (new_scale / prev_scale) + ) + end +end + +---Registers a new animation to be ran on the update cycle. +---@param target? table If nil assumes properties belong to widget it self. +---@param properties table +---@param options? widget.animation.options +function Widget:animate(target, properties, options) + if not target then target = self end + + -- if name is set then prevent adding if another one with the same + -- animation name is already running + if options and options.name then + for _, animation in ipairs(self.animations) do + if animation.options and animation.options.name == options.name then + return + end + end + end + + table.insert(self.animations, { + target = target, + properties = properties, + options = options + }) +end + +---Runs all registered animations removing duplicated and finished ones. +function Widget:run_animations() + if #self.animations > 0 then + ---@type table + local duplicates = {} + + local targets = {} + local deleted = 0 + for i=1, #self.animations do + local animation = self.animations[i - deleted] + + -- do not run animations that change same target to prevent conflicts. + if not targets[animation.target] then + local finished = true + local options = animation.options or {} + for name, value in pairs(animation.properties) do + if animation.target[name] ~= value then + self:move_towards(animation.target, name, value, options.rate) + if options.on_step then + options.on_step(animation.target, name, animation.target[name]) + end + if animation.target[name] ~= value then + finished = false + end + end + end + if finished then + if options.on_complete then + options.on_complete(self) + end + table.remove(self.animations, i - deleted) + deleted = deleted + 1 + end + targets[animation.target] = animation + -- only registers it as duplicated if the animation does needs to + -- perform any tasks on completion. + elseif not targets[animation.target].on_complete then + duplicates[targets[animation.target]] = animation + end + end + + -- remove older duplcated animations that modify same target and properties + for duplicate, newer_animation in pairs(duplicates) do + local exact_properties = true + for name, _ in pairs(duplicate.properties) do + if not newer_animation.properties[name] then + exact_properties = false + break + end + end + if exact_properties then + for name, _ in pairs(newer_animation.properties) do + if not duplicate.properties[name] then + exact_properties = false + break + end + end + end + if exact_properties then + for i, animation in ipairs(self.animations) do + if animation == duplicate then + table.remove(self.animations, i) + break + end + end + end + end + end +end + +---If visible execute the widget calculations and returns true. +---@return boolean +function Widget:update() + if not self:is_visible() then return false end + + Widget.super.update(self) + + -- call this to be able to properly scroll + self:update_position() + + -- run any pending animations + self:run_animations() + + for _, child in pairs(self.childs) do + child:update() + end + + return true +end + +function Widget:draw_scrollbar() + if self.scrollable then + Widget.super.draw_scrollbar(self) + end +end + +---If visible draw the widget and returns true. +---@return boolean +function Widget:draw() + if not self:is_visible() then return false end + + Widget.super.draw(self) + + self:draw_border() + + if self.render_background then + if self.background_color then + self:draw_background(self.background_color) + else + self:draw_background( + self.parent and style.background or style.background2 + ) + end + end + + if #self.childs > 0 then + core.push_clip_rect( + self.position.x, + self.position.y, + self.size.x, + self.size.y + ) + end + + for i=#self.childs, 1, -1 do + self.childs[i]:draw() + end + + if #self.childs > 0 then + core.pop_clip_rect() + end + + self:draw_scrollbar() + + return true +end + +---Recursively destroy all childs from the widget. +function Widget:destroy_childs() + for _=1, #self.childs do + self.childs[1]:destroy_childs() + table.remove(self.childs, 1) + end +end + +---If floating, remove the widget from the floating widgets list +---to allow proper garbage collection. +function Widget:destroy() + if not self.parent or self.defer_draw then + for idx, widget in ipairs(floating_widgets) do + if widget == self then + widget:destroy_childs() + floating_widgets[idx] = nil + table.remove(floating_widgets, idx) + break + end + end + end +end + +---Toggle the forced interception of given event even if all the conditions +---for emitting it are not met. +--- +---Note: only "mouse_released" is implemented for the moment on floating views +---for use in the SelectBox, maybe a better system can be implemented on +---the future. +---@param name "mouse_released" +---@param force boolean If omitted is set to true by default +function Widget:force_event(name, force) + if type(force) ~= "boolean" or force then + self.force_events[name] = true + else + self.force_events[name] = nil + end +end + +---Flag that indicates if the rootview events are already overrided. +---@type boolean +local root_overrided = false + +---Called when initializing a floating widget to generate RootView overrides, +---this function will only override the events once. +function Widget.override_rootview() + if root_overrided then return end + root_overrided = true + + if not RootView then RootView = require "core.rootview" end + + local root_view_on_mouse_pressed = RootView.on_mouse_pressed + local root_view_on_mouse_released = RootView.on_mouse_released + local root_view_on_mouse_moved = RootView.on_mouse_moved + local root_view_on_mouse_wheel = RootView.on_mouse_wheel + local root_view_update = RootView.update + local root_view_draw = RootView.draw + local root_view_on_file_dropped = RootView.on_file_dropped + local root_view_on_text_input = RootView.on_text_input + + function RootView:on_mouse_pressed(button, x, y, clicks) + local pressed = false + for i=#floating_widgets, 1, -1 do + local widget = floating_widgets[i] + if widget.visible then + widget.mouse_pressed_outside = not widget:mouse_on_top(x, y) + if + (not widget.defer_draw and not widget.child_active) + or + widget.mouse_pressed_outside + or + (pressed or not widget:on_mouse_pressed(button, x, y, clicks)) + then + widget:swap_active_child() + else + pressed = true + end + end + end + if not pressed then + return root_view_on_mouse_pressed(self, button, x, y, clicks) + else + return true + end + end + + function RootView:on_mouse_released(button, x, y) + local released = false + for i=#floating_widgets, 1, -1 do + local widget = floating_widgets[i] + if widget.visible then + if + (not widget.defer_draw and not widget.child_active) + or + ( + not widget.force_events["mouse_released"] + and + widget.mouse_pressed_outside + ) + or + not widget:on_mouse_released(button, x, y) + then + widget.mouse_pressed_outside = false + else + released = true + end + end + end + if not released then + root_view_on_mouse_released(self, button, x, y) + end + end + + function RootView:on_mouse_moved(x, y, dx, dy) + if core.active_view ~= core.command_view then + for i=#floating_widgets, 1, -1 do + local widget = floating_widgets[i] + if widget.visible then + if + (not widget.defer_draw and not widget.child_active) + or + widget.mouse_pressed_outside + or + not widget:on_mouse_moved(x, y, dx, dy) + then + if + not widget.is_scrolling and not widget.captured_widget + and + not widget.child_active and widget.outside_view + then + core.set_active_view(widget.outside_view) + widget.outside_view = nil + elseif widget.outside_view then + core.request_cursor("arrow") + end + else + if not widget.child_active and widget.defer_draw then + if not widget.outside_view then + widget.outside_view = core.active_view + end + core.set_active_view(widget) + end + return true + end + end + end + end + return root_view_on_mouse_moved(self, x, y, dx, dy) + end + + function RootView:on_mouse_wheel(y, x) + for i=#floating_widgets, 1, -1 do + local widget = floating_widgets[i] + if + widget.visible and widget.defer_draw and widget:on_mouse_wheel(y, x) + then + return true + end + end + return root_view_on_mouse_wheel(self, y, x) + end + + function RootView:on_file_dropped(filename, x, y) + for i=#floating_widgets, 1, -1 do + local widget = floating_widgets[i] + if + widget.visible and widget.defer_draw + and + widget:on_file_dropped(filename, x, y) + then + return true + end + end + return root_view_on_file_dropped(self, filename, x, y) + end + + function RootView:on_text_input(text) + for i=#floating_widgets, 1, -1 do + local widget = floating_widgets[i] + if + widget.visible and widget.defer_draw and widget:on_text_input(text) + then + return true + end + end + return root_view_on_text_input(self, text) + end + + function RootView:update() + root_view_update(self) + local count = #floating_widgets + for i=1, count, 1 do + local widget = floating_widgets[i] + if widget.visible and widget.defer_draw then + widget:update() + end + end + end + + function RootView:draw() + local count = #floating_widgets + for i=1, count, 1 do + local widget = floating_widgets[i] + if widget.visible and widget.defer_draw then + core.root_view:defer_draw(widget.draw, widget) + end + end + root_view_draw(self) + end +end + + +return Widget diff --git a/debian/extra/libraries/widget/inputdialog.lua b/debian/extra/libraries/widget/inputdialog.lua new file mode 100644 index 0000000..793dd8f --- /dev/null +++ b/debian/extra/libraries/widget/inputdialog.lua @@ -0,0 +1,88 @@ +-- +-- Input Dialog Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local style = require "core.style" +local Button = require "libraries.widget.button" +local Dialog = require "libraries.widget.dialog" +local Label = require "libraries.widget.label" +local TextBox = require "libraries.widget.textbox" + +---@class widget.inputdialog : widget.dialog +---@overload fun(title?:string, message?:string, text?:string):widget.inputdialog +---@field super widget.dialog +---@field message widget.label +---@field text widget.textbox +---@field save widget.button +---@field cancel widget.button +local InputDialog = Dialog:extend() + +---Constructor +---@param title string +---@param message string +---@param text string +function InputDialog:new(title, message, text) + InputDialog.super.new(self, title or "Enter Value") + + self.type_name = "widget.inputdialog" + + self.message = Label(self.panel, message) + self.text = TextBox(self.panel, text or "") + + local this = self + + self.save = Button(self.panel, "Save") + self.save:set_icon("S") + function self.save:on_click() + this:on_save(this.text:get_text()) + this:on_close() + end + + self.cancel = Button(self.panel, "Cancel") + self.cancel:set_icon("C") + function self.cancel:on_click() + this:on_close() + end +end + +---Called when the user clicks on save +---@param value string +function InputDialog:on_save(value) end + +function InputDialog:update() + if not InputDialog.super.update(self) then return false end + + self.message:set_position(style.padding.x/2, 0) + self.text:set_position(style.padding.x/2, self.message:get_bottom() + style.padding.y) + + self.save:set_position( + style.padding.x/2, + self.text:get_bottom() + style.padding.y + ) + self.cancel:set_position( + self.save:get_right() + style.padding.x, + self.text:get_bottom() + style.padding.y + ) + + self.panel.size.x = self.panel:get_real_width() + style.padding.x + self.panel.size.y = self.panel:get_real_height() + self.size.x = self:get_real_width() - (style.padding.x / 2) + self.size.y = self:get_real_height() + (style.padding.y / 2) + + self.text:set_size( + self.size.x - style.padding.x, + self.text:get_real_height() + ) + + self.close:set_position( + self.size.x - self.close.size.x - (style.padding.x / 2), + style.padding.y / 2 + ) + + return true +end + + +return InputDialog diff --git a/debian/extra/libraries/widget/itemslist.lua b/debian/extra/libraries/widget/itemslist.lua new file mode 100644 index 0000000..5e706c2 --- /dev/null +++ b/debian/extra/libraries/widget/itemslist.lua @@ -0,0 +1,162 @@ +-- +-- ItemsList Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- +local style = require "core.style" +local Widget = require "libraries.widget" +local Button = require "libraries.widget.button" +local ListBox = require "libraries.widget.listbox" +local InputDialog = require "libraries.widget.inputdialog" +local MessageBox = require "libraries.widget.messagebox" + +---@class widget.itemslist : widget +---@overload fun(parent:widget?):widget.itemslist +---@field list widget.listbox +---@field add widget.button +---@field remove widget.button +local ItemsList = Widget:extend() + +---Constructor +---@param parent widget +function ItemsList:new(parent) + ItemsList.super.new(self, parent) + + self.type_name = "widget.itemslist" + + self.border.width = 0 + + self.dialog = false + + self.list = ListBox(self) + + local this = self + + function self.list:on_mouse_pressed(button, x, y, clicks) + if not ListBox.on_mouse_pressed(self, button, x, y, clicks) then + return false + end + + if clicks == 2 and not this.dialog then + this.dialog = true + local selected = this.list:get_selected() + local selvalue = this.list:get_row_text(selected) + ---@type widget.inputdialog + local input = InputDialog("Edit Item", "Enter the new item value:", selvalue) + function input:on_save(value) + this:edit_item(selected, value) + end + function input:on_close() + InputDialog.on_close(self) + self:destroy() + this.dialog = false + end + input:show() + end + + return true + end + + self.add = Button(self, "Add") + self.add:set_icon("B") + function self.add:on_click() + if not this.dialog then + ---@type widget.inputdialog + local input = InputDialog("Add Item", "Enter the new item:") + function input:on_save(value) + this:add_item(value) + end + function input:on_close() + InputDialog.on_close(self) + self:destroy() + this.dialog = false + end + input:show() + end + end + + self.remove = Button(self, "Remove") + self.remove:set_icon("C") + function self.remove:on_click() + local selected = this.list:get_selected() + if selected then + this:remove_item(selected) + else + MessageBox.error("No item selected", "Please select an item to remove") + end + end +end + +---Add a new item into the list. +---@param text widget.styledtext | string +---@param data any +function ItemsList:add_item(text, data) + if type(text) == "string" then + text = {text} + end + self.list:add_row(text, data) + self.list:set_visible_rows() + self:on_change() +end + +---Edit an existing item on the list. +---@param idx integer +---@param text widget.styledtext | string +---@param data any +function ItemsList:edit_item(idx, text, data) + if type(text) == "string" then + text = {text} + end + self.list:set_row(idx, text) + if data then + self.list:set_row_data(idx, data) + end + self:on_change() +end + +---Remove the given item from the list. +---@param idx integer +function ItemsList:remove_item(idx) + self.list:remove_row(idx) + self:on_change() +end + +---Return the items from the list. +---@return table +function ItemsList:get_items() + local output = {} + local count = #self.list.rows + for i=1, count, 1 do + table.insert(output, self.list:get_row_text(i)) + end + return output +end + +function ItemsList:update() + if not ItemsList.super.update(self) then return false end + + if self.size.x == 0 then + self.size.x = self.add:get_width() + + (style.padding.x / 2) + self.remove:get_width() + (50 * SCALE) + self.size.y = self.add:get_height() + (style.padding.y * 2) + 100 + end + + self.list:set_position(0, 0) + + self.list:set_size( + self.size.x, + self.size.y - self.add:get_height() - (style.padding.y * 2) + ) + + self.add:set_position(0, self.list:get_bottom() + style.padding.y) + + self.remove:set_position( + self.add:get_right() + (style.padding.x / 2), + self.list:get_bottom() + style.padding.y + ) + + return true +end + + +return ItemsList diff --git a/debian/extra/libraries/widget/keybinddialog.lua b/debian/extra/libraries/widget/keybinddialog.lua new file mode 100644 index 0000000..c54f8ab --- /dev/null +++ b/debian/extra/libraries/widget/keybinddialog.lua @@ -0,0 +1,257 @@ +-- +-- KeyBinding Dialog Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local keymap = require "core.keymap" +local style = require "core.style" +local Button = require "libraries.widget.button" +local Dialog = require "libraries.widget.dialog" +local Label = require "libraries.widget.label" +local Line = require "libraries.widget.line" +local ListBox = require "libraries.widget.listbox" +local MessageBox = require "libraries.widget.messagebox" + +---@type widget.keybinddialog +local current_dialog = nil + +---@class widget.keybinddialog : widget.dialog +---@overload fun():widget.keybinddialog +---@field super widget.dialog +---@field selected integer +---@field shortcuts widget.listbox +---@field add widget.button +---@field remove widget.button +---@field line widget.line +---@field message widget.label +---@field binding widget.label +---@field mouse_intercept widget.label +---@field save widget.button +---@field reset widget.button +---@field cancel widget.button +local KeybindDialog = Dialog:extend() + +---Constructor +function KeybindDialog:new() + KeybindDialog.super.new(self, "Keybinding Selector") + + self.type_name = "widget.keybinddialog" + + self.selected = nil + + local this = self + + self.shortcuts = ListBox(self.panel) + self.shortcuts:set_size(100, 100) + function self.shortcuts:on_row_click(idx, data) + this.selected = idx + end + + self.add = Button(self.panel, "Add") + self.add:set_icon("B") + function self.add:on_click() + this.shortcuts:add_row({"none"}) + this.shortcuts:set_selected(#this.shortcuts.rows) + this.shortcuts:set_visible_rows() + this.selected = #this.shortcuts.rows + end + + self.remove = Button(self.panel, "Remove") + self.remove:set_icon("C") + function self.remove:on_click() + local selected = this.shortcuts:get_selected() + if selected then + this.shortcuts:remove_row(selected) + this.shortcuts:set_selected(nil) + this.selected = nil + else + MessageBox.error("No shortcut selected", "Please select an shortcut to remove") + end + end + + self.line = Line(self.panel) + + self.message = Label(self.panel, "Press a key combination to change selected") + + self.mouse_intercept = Label(self.panel, "Grab mouse events here") + self.mouse_intercept.border.width = 1 + self.mouse_intercept.clickable = true + self.mouse_intercept:set_size(100, 100) + function self.mouse_intercept:on_mouse_pressed(button, x, y, clicks) + keymap.on_mouse_pressed(button, x, y, clicks) + return true + end + function self.mouse_intercept:on_mouse_wheel(y) + keymap.on_mouse_wheel(y) + return true + end + function self.mouse_intercept:on_mouse_enter(...) + Label.super.on_mouse_enter(self, ...) + self.border.color = style.caret + end + function self.mouse_intercept:on_mouse_leave(...) + Label.super.on_mouse_leave(self, ...) + self.border.color = style.text + end + + self.save = Button(self.panel, "Save") + self.save:set_icon("S") + function self.save:on_click() + this:on_save(this:get_bindings()) + this:on_close() + end + + self.reset = Button(self.panel, "Reset") + function self.reset:on_click() + this:on_reset() + this:on_close() + end + + self.cancel = Button(self.panel, "Cancel") + self.cancel:set_icon("C") + function self.cancel:on_click() + this:on_close() + end +end + +---@param bindings table +function KeybindDialog:set_bindings(bindings) + self.shortcuts:clear() + for _, binding in ipairs(bindings) do + self.shortcuts:add_row({binding}) + end + if #bindings > 0 then + self.shortcuts:set_selected(1) + self.selected = 1 + end + self.shortcuts:set_visible_rows() +end + +---@return table +function KeybindDialog:get_bindings() + local bindings = {} + for idx=1, #self.shortcuts.rows, 1 do + table.insert(bindings, self.shortcuts:get_row_text(idx)) + end + return bindings +end + +---Show the dialog and enable key interceptions +function KeybindDialog:show() + current_dialog = self + KeybindDialog.super.show(self) +end + +---Hide the dialog and disable key interceptions +function KeybindDialog:hide() + current_dialog = nil + KeybindDialog.super.hide(self) +end + +---Called when the user clicks on save +---@param bindings string +function KeybindDialog:on_save(bindings) end + +---Called when the user clicks on reset +function KeybindDialog:on_reset() end + +function KeybindDialog:update() + if not KeybindDialog.super.update(self) then return false end + + self.shortcuts:set_position(style.padding.x/2, 0) + + self.add:set_position( + style.padding.x/2, + self.shortcuts:get_bottom() + style.padding.y + ) + + self.remove:set_position( + self.add:get_right() + (style.padding.x/2), + self.shortcuts:get_bottom() + style.padding.y + ) + + self.line:set_position( + 0, + self.remove:get_bottom() + style.padding.y + ) + + self.message:set_position( + style.padding.x/2, + self.line:get_bottom() + style.padding.y + ) + self.mouse_intercept:set_position( + style.padding.x/2, + self.message:get_bottom() + style.padding.y + ) + + self.save:set_position( + style.padding.x/2, + self.mouse_intercept:get_bottom() + style.padding.y + ) + self.reset:set_position( + self.save:get_right() + style.padding.x, + self.mouse_intercept:get_bottom() + style.padding.y + ) + self.cancel:set_position( + self.reset:get_right() + style.padding.x, + self.mouse_intercept:get_bottom() + style.padding.y + ) + + self.panel.size.x = self.panel:get_real_width() + style.padding.x + self.panel.size.y = self.panel:get_real_height() + self.size.x = self:get_real_width() - (style.padding.x / 2) + self.size.y = self:get_real_height() + (style.padding.y / 2) + + self.shortcuts:set_size(self.size.x - style.padding.x) + + self.line:set_width(self.size.x - style.padding.x) + + self.mouse_intercept:set_size(self.size.x - style.padding.x) + + return true +end + +-------------------------------------------------------------------------------- +-- Intercept keymap events +-------------------------------------------------------------------------------- + +-- Same declarations as in core.keymap because modkey_map is not public +local macos = PLATFORM == "Mac OS X" +local modkeys_os = require("core.modkeys-" .. (macos and "macos" or "generic")) +local modkey_map = modkeys_os.map +local modkeys = modkeys_os.keys + +---Copied from core.keymap because it is not public +local function key_to_stroke(k) + local stroke = "" + for _, mk in ipairs(modkeys) do + if keymap.modkeys[mk] then + stroke = stroke .. mk .. "+" + end + end + return stroke .. k +end + +local keymap_on_key_pressed = keymap.on_key_pressed +function keymap.on_key_pressed(k, ...) + if current_dialog and current_dialog.selected then + local mk = modkey_map[k] + if mk then + keymap.modkeys[mk] = true + -- work-around for windows where `altgr` is treated as `ctrl+alt` + if mk == "altgr" then + keymap.modkeys["ctrl"] = false + end + current_dialog.shortcuts:set_row(current_dialog.selected, {key_to_stroke("")}) + else + current_dialog.shortcuts:set_row(current_dialog.selected, {key_to_stroke(k)}) + end + return true + else + return keymap_on_key_pressed(k, ...) + end +end + + +return KeybindDialog diff --git a/debian/extra/libraries/widget/label.lua b/debian/extra/libraries/widget/label.lua new file mode 100644 index 0000000..1c05264 --- /dev/null +++ b/debian/extra/libraries/widget/label.lua @@ -0,0 +1,95 @@ +-- +-- Label Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local style = require "core.style" +local Widget = require "libraries.widget" + +---@class widget.label : widget +---@overload fun(parent:widget?, label?:string):widget.label +---@field clickable boolean +local Label = Widget:extend() + +---Constructor +---@param parent widget +---@param label string +function Label:new(parent, label) + Label.super.new(self, parent) + self.type_name = "widget.label" + self.clickable = false + self.border.width = 0 + self.custom_size = {x = 0, y = 0} + + self:set_label(label or "") +end + +---@param width? integer +---@param height? integer +function Label:set_size(width, height) + Label.super.set_size(self, width, height) + self.custom_size.x = self.size.x + self.custom_size.y = self.size.y +end + +---Set the label text and recalculates the widget size. +---@param text string|widget.styledtext +function Label:set_label(text) + Label.super.set_label(self, text) + + local font = self:get_font() + + if self.custom_size.x <= 0 then + if type(text) == "table" then + self.size.x, self.size.y = self:draw_styled_text(text, 0, 0, true) + else + self.size.x = font:get_width(self.label) + self.size.y = font:get_height() + end + + if self.border.width > 0 then + self.size.x = self.size.x + style.padding.x + self.size.y = self.size.y + style.padding.y + end + end +end + +function Label:update() + if not Label.super.update(self) then return false end + + if self.custom_size.x <= 0 then + -- update the size + self:set_label(self.label) + end + + return true +end + +function Label:draw() + if not self:is_visible() then return false end + + self:draw_border() + + local px = self.border.width > 0 and (style.padding.x / 2) or 0 + local py = self.border.width > 0 and (style.padding.y / 2) or 0 + + local posx, posy = self.position.x + px, self.position.y + py + + if type(self.label) == "table" then + self:draw_styled_text(self.label, posx, posy) + else + renderer.draw_text( + self:get_font(), + self.label, + posx, + posy, + self.foreground_color or style.text + ) + end + + return true +end + + +return Label diff --git a/debian/extra/libraries/widget/line.lua b/debian/extra/libraries/widget/line.lua new file mode 100644 index 0000000..a5152f3 --- /dev/null +++ b/debian/extra/libraries/widget/line.lua @@ -0,0 +1,61 @@ +-- +-- Line Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local style = require "core.style" +local Widget = require "libraries.widget" + +---@class widget.line : widget +---@overload fun(parent?:widget, thickness?:integer, padding?:number):widget.line +---@field public padding integer +---@field private custom_width number +local Line = Widget:extend() + +---Constructor +---@param parent widget +---@param thickness integer +---@param padding number +function Line:new(parent, thickness, padding) + Line.super.new(self, parent) + self.type_name = "widget.line" + self.size.y = thickness or 2 + self.custom_width = nil + self.border.width = 0 + self.padding = padding or (style.padding.x / 2) +end + +---Set the thickness of the line +---@param thickness number +function Line:set_thickness(thickness) + self.size.y = thickness or 2 +end + +---Set a custom width for the line +---@param width number +function Line:set_width(width) + self.custom_width = width + self.size.x = width +end + +function Line:draw() + if not self:is_visible() then return false end + + if not self.custom_width then + self.size.x = self.parent.size.x - (self.padding * 2) + end + + renderer.draw_rect( + self.position.x + self.padding, + self.position.y, + self.size.x, + self.size.y, + self.foreground_color or style.caret + ) + + return true +end + + +return Line diff --git a/debian/extra/libraries/widget/listbox.lua b/debian/extra/libraries/widget/listbox.lua new file mode 100644 index 0000000..2b5333a --- /dev/null +++ b/debian/extra/libraries/widget/listbox.lua @@ -0,0 +1,926 @@ +-- +-- ListBox Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local core = require "core" +local style = require "core.style" +local Widget = require "libraries.widget" +local MessageBox = require "libraries.widget.messagebox" + +---@class widget.listbox.column +---@field public name string +---@field public width string +---@field public expand boolean +---@field public longest integer + +---@alias widget.listbox.drawcol fun(self, row, x, y, font, color, only_calc) +---@alias widget.listbox.filtercb fun(self:widget.listbox, idx:integer, row:widget.listbox.row, data:any):number? + +---@alias widget.listbox.row table + +---@alias widget.listbox.colpos table + +---@class widget.listbox : widget +---@overload fun(parent:widget?):widget.listbox +---@field rows widget.listbox.row[] +---@field private row_data any +---@field private rows_original widget.listbox.row[] +---@field private row_data_original any +---@field private columns widget.listbox.column[] +---@field private positions widget.listbox.colpos[] +---@field private mouse widget.position +---@field private selected_row integer +---@field private hovered_row integer +---@field private largest_row integer +---@field private expand boolean +---@field private visible_rows table +---@field private visible_rendered boolean +---@field private last_scale integer +---@field private last_offset integer +local ListBox = Widget:extend() + +---Indicates on a widget.listbox.row that the end +---of a column was reached. +---@type integer +ListBox.COLEND = 1 + +---Indicates on a widget.listbox.row that a new line +---follows while still rendering the same column. +---@type integer +ListBox.NEWLINE = 2 + +---Constructor +---@param parent widget +function ListBox:new(parent) + ListBox.super.new(self, parent) + self.type_name = "widget.listbox" + self.scrollable = true + self.rows = {} + self.row_data = {} + self.rows_original = {} + self.row_data_original = {} + self.rows_idx_original = {} + self.columns = {} + self.positions = {} + self.selected_row = 0 + self.hovered_row = 0 + self.largest_row = 0 + self.expand = false + self.visible_rows = {} + self.visible_rendered = false + self.last_scale = 0 + self.last_offset = 0 + + self:set_size(200, (self:get_font():get_height() + (style.padding.y*2)) * 3) +end + +---Set which rows to show using the specified match string or callback, +---if nil all rows are restored. +---@param match? string | widget.listbox.filtercb +function ListBox:filter(match) + if (not match or match == "") and #self.rows_original > 0 then + self:clear() + for idx, row in ipairs(self.rows_original) do + self:add_row(row, self.row_data_original[idx]) + end + self.rows_original = {} + self.row_data_original = {} + self.rows_idx_original = {} + return + elseif match and match ~= "" then + self.rows_original = #self.rows_original > 0 + and self.rows_original or self.rows + self.row_data_original = #self.row_data_original > 0 + and self.row_data_original or self.row_data + self.rows_idx_original = {} + + self:clear() + + local match_type = type(match) + + local rows = {} + for idx, row in ipairs(self.rows_original) do + local score + if match_type == "function" then + score = match(self, idx, row, self.row_data_original[idx]) + else + score = system.fuzzy_match(self:get_row_text(row), match, false) + end + if score then + table.insert(rows, {row, self.row_data_original[idx], score, idx}) + end + end + + table.sort(rows, function(a, b) return a[3] > b[3] end) + + for _, row in ipairs(rows) do + self:add_row(row[1], row[2]) + table.insert(self.rows_idx_original, row[4]) + end + end +end + +---If no width is given column will be set to automatically +---expand depending on the longest element +---@param name string +---@param width? number +---@param expand? boolean +function ListBox:add_column(name, width, expand) + local column = { + name = name, + width = width or self:get_font():get_width(name), + expand = expand and expand or (width and false or true) + } + + table.insert(self.columns, column) +end + +---You can give it a table a la statusview style where you pass elements +---like fonts, colors, ListBox.COLEND, ListBox.NEWLINE and multiline strings. +---@param row widget.listbox.row +---@param data any Associated with the row and given to on_row_click() +function ListBox:add_row(row, data) + table.insert(self.rows, row) + table.insert(self.positions, self:get_col_positions(row)) + + if type(data) ~= "nil" then + self.row_data[#self.rows] = data + end + + -- increase columns width if needed + if #self.columns > 0 then + local ridx = #self.rows + for col, pos in ipairs(self.positions[ridx]) do + if self.columns[col].expand then + local w = self:draw_row_range(ridx, row, pos[1], pos[2], 1, 1, true) + + -- store the row with longest column for cheaper calculation + self.columns[col].width = math.max(self.columns[col].width, w) + if self.columns[col].width < w then + self.columns[col].longest = ridx + end + end + end + end + + -- precalculate the row size and position + self:calc_row_size_pos(#self.rows) +end + +---Calculate a row position and size and store it on the row it +---self on the fields x, y, w, h +---@param ridx integer +function ListBox:calc_row_size_pos(ridx) + local x = self.border.width + local y = self.border.width + + if ridx == 1 then + -- if columns are enabled leave some space to render them + if #self.columns > 0 then + y = y + self:get_font():get_height() + style.padding.y + end + else + y = y + self.rows[ridx-1].y + self.rows[ridx-1].h + end + + self:draw_row(ridx, x, y, true) +end + +---Recalculate all row sizes and positions which should be only required +---when lite-xl ui scale changes or a row is removed from the list +function ListBox:recalc_all_rows() + for ridx, _ in ipairs(self.rows) do + self:calc_row_size_pos(ridx) + end +end + +---Calculates the scrollable size based on the last row of the list. +---@return number +function ListBox:get_scrollable_size() + local size = self.size.y + local rows = #self.rows + if rows > 0 and self.rows[rows].y then + size = math.max(size, self.rows[rows].y + self.rows[rows].h) + end + return size +end + +function ListBox:get_h_scrollable_size() + local size = self.size.x + local rows = #self.rows + if rows > 0 and self.rows[rows].x then + size = math.max(size, self.rows[rows].x + self.rows[rows].w) + end + return size +end + +---Detects the rows that are visible each time the content is scrolled, +---this way the draw function will only process the visible rows. +function ListBox:set_visible_rows() + local _, oy = self:get_content_offset() + local h = self.size.y + + -- substract column heading from list height + local colh = 0 + if #self.columns > 0 then + colh = self:get_font():get_height() + style.padding.y + h = h - colh + end + + -- start from nearest row relative to scroll direction for + -- better performance on long lists + local idx, total, step = 1, #self.rows, 1 + if #self.visible_rows > 0 then + if oy < self.last_offset or not self.visible_rendered then + idx = self.visible_rows[1] + self.visible_rendered = true + else + idx = self.visible_rows[#self.visible_rows] + total = 1 + step = -1 + end + end + + oy = oy - self.position.y + + self.visible_rows = {} + local first_visible = false + local height = 0 + for i=idx, total, step do + local row = self.rows[i] + if row then + local top = row.y - colh + row.h + oy + local visible = false + local visible_area = h - top + if top < 0 and (top + row.h) > 0 then + visible = true + elseif top >= 0 and top < h then + visible = true + end + if visible and height <= h then + table.insert(self.visible_rows, i) + first_visible = true + -- store only the visible height + if top < 0 then + height = height + (top + row.h) + else + if visible_area > row.h then + height = height + row.h + else + height = height + visible_area + end + end + elseif first_visible then + table.insert(self.visible_rows, i) + break + end + end + end + + -- append one more row if possible to fill possible empty spaces of + -- incomplete row height calculation above (bad math skills workarounds) + local last_row = self.visible_rows[#self.visible_rows] + local first_row = self.visible_rows[1] + if #self.visible_rows > 0 then + if step == 1 then + if self.rows[last_row+1] then + table.insert(self.visible_rows, last_row+1) + end + else + if self.rows[first_row-2] and first_row-2 ~= 1 then + table.insert(self.visible_rows, first_row-2) + elseif self.rows[last_row+1] then + table.insert(self.visible_rows, last_row+1) + end + + -- sort for proper subsequent loop interations + table.sort( + self.visible_rows, + function(val1, val2) return val1 < val2 end + ) + + local frow = self.visible_rows[1] + for i, _ in ipairs(self.visible_rows) do + if self.rows[frow] then + self.visible_rows[i] = frow + frow = frow + 1 + end + end + if #self.visible_rows > 1 then + if + self.visible_rows[#self.visible_rows] + == + self.visible_rows[#self.visible_rows-1] + then + table.remove(self.visible_rows, #self.visible_rows) + end + end + end + end +end + +-- Solution to safely remove elements from array table: +-- found at https://stackoverflow.com/a/53038524 +local function array_remove(t, fnKeep) + local j, n = 1, #t; + + for i=1, n do + if (fnKeep(t, i, j)) then + if (i ~= j) then + t[j] = t[i]; + t[i] = nil; + end + j = j + 1; + else + t[i] = nil; + end + end + + return t; +end + +---Remove a given row index from the list. +---@param ridx integer +function ListBox:remove_row(ridx) + if not self.rows[ridx] then return end + + if #self.rows_idx_original > 0 then + MessageBox.error( + "Can not remove row", + "Rows can not be removed when the list is filtered." + ) + return + end + + local last_col = false + local row_y = self.rows[ridx].y + local row_h = self.rows[ridx].h + if ridx == #self.rows then + last_col = true + end + + local fields = { "rows", "positions", "row_data" } + for _, field in ipairs(fields) do + array_remove(self[field], function(_, i, _) + if i == ridx then + return false + end + return true + end) + end + for _, col in ipairs(self.columns) do + if col.longest == ridx then + col.longest = nil + end + end + + if not last_col and #self.rows > 0 then + for idx=ridx, #self.rows, 1 do + self.rows[idx].y = self.rows[idx].y - row_h + end + end + + local visible_removed = false + array_remove(self.visible_rows, function(t, i, _) + if t[i] == ridx then + visible_removed = true + return false + end + return true + end) + + -- make visible rows sequence correctly incremental + if visible_removed and #self.visible_rows > 0 then + local first_row = self.visible_rows[1] + for i, _ in ipairs(self.visible_rows) do + self.visible_rows[i] = first_row + first_row = first_row + 1 + end + self:set_visible_rows() + end +end + +---Set the row that is currently active/selected. +---@param idx? integer +function ListBox:set_selected(idx) + self.selected_row = idx or 0 +end + +---Get the row that is currently active/selected. +---@return integer | nil +function ListBox:get_selected() + if self.selected_row > 0 then + return self.selected_row + end + return nil +end + +---Change the content assigned to a row. +---@param idx integer +---@param row widget.listbox.row +function ListBox:set_row(idx, row) + --TODO: recalculate subsequent row sizes and max col width if needed + if self.rows[idx] then + self.rows[idx] = row + if #self.rows_idx_original > 0 then + self.rows_original[self.rows_idx_original[idx]] = row + end + -- precalculate the row size and position + self:calc_row_size_pos(idx) + end +end + +---Change the data assigned to a row. +---@param idx integer +---@param data any|nil +function ListBox:set_row_data(idx, data) + if self.rows[idx] then + self.row_data[idx] = data + if #self.rows_idx_original > 0 then + self.row_data_original[self.rows_idx_original[idx]] = data + end + end +end + +---Get the data associated with a row. +---@param idx integer +---@return any|nil +function ListBox:get_row_data(idx) + if type(self.row_data[idx]) ~= "nil" then + return self.row_data[idx] + end + return nil +end + +---Get the text only of a styled row. +---@param row integer | table +---@return string +function ListBox:get_row_text(row) + local text = "" + row = type(row) == "table" and row or self.rows[row] + if row then + for _, element in ipairs(row) do + if type(element) == "string" then + text = text .. element + elseif element == ListBox.NEWLINE then + text = text .. "\n" + end + end + end + return text +end + +---Get the starting and ending position of columns in a row table. +---@param row widget.listbox.row +---@return widget.listbox.colpos +function ListBox:get_col_positions(row) + local positions = {} + local idx = 1 + local idx_start = 1 + local row_len = #row + + for _, element in ipairs(row) do + if element == ListBox.COLEND then + table.insert(positions, { idx_start, idx-1 }) + idx_start = idx + 1 + elseif idx == row_len then + table.insert(positions, { idx_start, idx }) + end + idx = idx + 1 + end + + return positions +end + +---Move a row to the desired position if possible. +---@param idx integer +---@param pos integer +---@return boolean moved +function ListBox:move_row_to(idx, pos) + if idx == pos or (pos == #self.rows and #self.rows == 1) then return false end + + if pos < 1 then pos = 1 end + + local row = table.remove(self.rows, idx) + local position = table.remove(self.positions, idx) + + if pos <= #self.rows then + table.insert(self.rows, pos, row) + table.insert(self.positions, pos, position) + else + table.insert(self.rows, row) + table.insert(self.positions, position) + pos = #self.rows + end + + local moved_row_data = self.row_data[idx] + local swapped_row_data = self.row_data[pos] + self.row_data[idx] = swapped_row_data + self.row_data[pos] = moved_row_data + + self.selected_row = pos + + self:recalc_all_rows() + self:set_visible_rows() + + return true +end + +---Move a row one position up if possible. +---@param idx integer +---@return boolean moved +function ListBox:move_row_up(idx) + return self:move_row_to(idx, idx-1) +end + +---Move a row one position down if possible. +---@param idx integer +---@return boolean moved +function ListBox:move_row_down(idx) + self:move_row_to(idx, idx+1) +end + +---Enables expanding the element to total size of parent on content updates. +function ListBox:enable_expand(expand) + self.expand = expand + if expand then + self:resize_to_parent() + end +end + +---Resizes the listbox to match the parent size +function ListBox:resize_to_parent() + self.size.x = self.parent.size.x + - (self.border.width * 2) + + self.size.y = self.parent.size.y + - (self.border.width * 2) + + self:set_visible_rows() +end + +---Remove all the rows from the listbox. +function ListBox:clear() + self.rows = {} + self.row_data = {} + self.positions = {} + self.selected_row = 0 + self.hovered_row = 0 + + for cidx, col in ipairs(self.columns) do + col.width = self:get_col_width(cidx) + col.longest = nil + end + + self:set_visible_rows() +end + +---Render or calculate the size of the specified range of elements in a row. +---@param ridx integer +---@param row widget.listbox.row +---@param start_idx integer +---@param end_idx integer +---@param x integer +---@param y integer +---@param only_calc boolean +---@return integer width +---@return integer height +function ListBox:draw_row_range(ridx, row, start_idx, end_idx, x, y, only_calc) + local font = self:get_font() + local color = self.foreground_color or style.text + local width = 0 + local height = font:get_height() + local new_line = false + local nx = x + + for pos=start_idx, end_idx, 1 do + local element = row[pos] + local ele_type = type(element) + if + ele_type == "userdata" + or + ( + ele_type == "table" + and + (element.container or type(element[1]) == "userdata") + ) + then + if ele_type == "table" and element.container then + font = element.container[element.name] + else + font = element + end + elseif ele_type == "table" then + color = element + elseif element == ListBox.NEWLINE then + y = y + font:get_height() + nx = x + new_line = true + elseif ele_type == "function" then + local w, h = element(self, ridx, nx, y, font, color, only_calc) + nx = nx + width + height = math.max(height, h) + width = width + w + elseif ele_type == "string" then + local rx, ry, w, h = self:draw_text_multiline( + font, element, nx, y, color, only_calc + ) + y = ry + nx = rx + if new_line then + height = height + h + width = math.max(width, w) + new_line = false + else + height = math.max(height, h) + width = width + w + end + end + end + + return width, height +end + +---Calculate the overall width of a column. +---@param col integer +---@return number +function ListBox:get_col_width(col) + if self.columns[col] then + if not self.columns[col].expand then + return self.columns[col].width + else + -- if longest is available don't iterate the entire row list + if self.columns[col].longest then + local id = self.columns[col].longest + local width = self:draw_row_range( + id, + self.rows[id], + self.positions[id][col][1], + self.positions[id][col][2], + 1, + 1, + true + ) + return width + end + + local width = self:get_font():get_width(self.columns[col].name) + for id, row in ipairs(self.rows) do + local w, h = self:draw_row_range( + id, + row, + self.positions[id][col][1], + self.positions[id][col][2], + 1, + 1, + true + ) + width = math.max(width, w) + end + return width + end + end + return 0 +end + +---Draw the column headers of the list if available +---@param w integer +---@param h integer +---@param ox number Horizontal offset +function ListBox:draw_header(w, h, ox) + local x = self.position.x + local y = self.position.y + renderer.draw_rect(x, y, w, h, style.background2) + x = ox + self.position.x + for _, col in ipairs(self.columns) do + renderer.draw_text( + self:get_font(), + col.name, + x + style.padding.x / 2, + y + style.padding.y / 2, + style.accent + ) + x = x + col.width + style.padding.x + end +end + +---Draw or calculate the dimensions of the given row position and stores +---the size and position on the row it self. +---@param row integer +---@param x integer +---@param y integer +---@param only_calc? boolean +---@return integer width +---@return integer height +function ListBox:draw_row(row, x, y, only_calc) + local w, h = 0, 0 + + if not only_calc and self.rows[row].w then + w, h = self.rows[row].w, self.rows[row].h + w = self.largest_row > 0 and self.largest_row or w + + if self.selected_row == row then + renderer.draw_rect(x, y, w, h, style.selection) + end + + local mouse = self.mouse + if + mouse.x >= x + and + mouse.x <= x + w + and + mouse.y >= y + and + mouse.y <= y + h + then + renderer.draw_rect(x, y, w, h, style.line_highlight) + self.hovered_row = row + end + w, h = 0, 0 + end + + -- add padding on top + y = y + (style.padding.y / 2) + + if #self.columns > 0 then + for col, coldata in ipairs(self.columns) do + -- padding on left + w = w + style.padding.x / 2 + local cw, ch = self:draw_row_range( + row, + self.rows[row], + self.positions[row][col][1], + self.positions[row][col][2], + x + w, + y, + only_calc + ) + -- add column width and end with padding on right + w = w + coldata.width + (style.padding.x / 2) + -- only store column height if bigger than previous one + h = math.max(h, ch) + end + else + local cw, ch = self:draw_row_range( + row, + self.rows[row], + 1, + #self.rows[row], + x + style.padding.x / 2, + y, + only_calc + ) + h = ch + w = cw + style.padding.x + end + + -- Add padding on top and bottom + h = h + style.padding.y + + if only_calc or not self.rows[row].w then + -- store the dimensions for inexpensive subsequent hover calculation + self.rows[row].w = w + self.rows[row].h = h + + -- TODO: performance improvement, render only the visible rows on the view? + self.rows[row].x = x + self.rows[row].y = y - (style.padding.y / 2) + end + + -- return height with padding on top and bottom + return w, h +end + +--- +--- Events +--- + +function ListBox:on_mouse_leave(x, y, dx, dy) + ListBox.super.on_mouse_leave(self, x, y, dx, dy) + self.hovered_row = 0 +end + +function ListBox:on_mouse_moved(x, y, dx, dy) + ListBox.super.on_mouse_moved(self, x, y, dx, dy) + self.hovered_row = 0 +end + +function ListBox:on_click(button, x, y) + if button == "left" and self.hovered_row > 0 then + self.selected_row = self.hovered_row + self:on_row_click(self.hovered_row, self.row_data[self.hovered_row]) + end +end + +---You can overwrite this to listen to item clicks +---@param idx integer +---@param data any Data associated with the row +function ListBox:on_row_click(idx, data) end + +function ListBox:update() + if not ListBox.super.update(self) then return false end + + -- only calculate columns width on scale change since this can be expensive + if self.last_scale ~= SCALE then + if #self.columns > 0 then + for col, column in ipairs(self.columns) do + column.width = self:get_col_width(col) + end + end + self:recalc_all_rows() + self.last_scale = SCALE + end + + local _, oy = self:get_content_offset() + if self.last_offset ~= oy then + self:set_visible_rows() + self.last_offset = oy + end + + return true +end + +function ListBox:draw() + if not ListBox.super.draw(self) then return false end + + if #self.rows > 0 and #self.visible_rows <= 0 then + self:set_visible_rows() + end + + local new_width = 0 + local new_height = 0 + local font = self:get_font() + + if #self.columns > 0 then + new_height = new_height + font:get_height() + style.padding.y + for _, col in ipairs(self.columns) do + new_width = new_width + col.width + style.padding.x + end + end + + if self.expand then + self:resize_to_parent() + + self.largest_row = self.size.x + - (self.parent.border.width * 2) + end + + -- Normalize the offset position + local opx, opy = self.parent:get_content_offset() + if not self.parent.parent and not self.defer_draw then + -- TODO: inspect why is this workaround needed + -- Without it wrong offset occurs on child listviews of a single parent + -- like in the case of the recent projects in EmptyView. + opy = 0 + end + + local ox, oy = self:get_content_offset() + + oy = oy - opy + if #self.visible_rows > 0 then + oy = oy + (self.rows[self.visible_rows[1]].y - new_height) + end + oy = oy - (self.position.y - self.parent.position.y) + + ox = ox - opx + ox = ox - (self.position.x - self.parent.position.x) + + local x = ox + self.position.x + self.border.width + local y = oy + self.position.y + self.border.width + new_height + + core.push_clip_rect( + self.position.x, self.position.y, self.size.x, self.size.y + ) + for _, ridx in ipairs(self.visible_rows) do + if self.rows[ridx] then + local w, h = self:draw_row(ridx, x, y) + new_width = math.max(new_width, w) + new_height = new_height + h + y = y + h + end + end + + if not self.expand then + self.largest_row = self:get_width() - (self.border.width*2) + self.size.x = self.largest_row + end + + if #self.columns > 0 then + self:draw_header( + self.largest_row, + font:get_height() + style.padding.y, + ox + ) + end + core.pop_clip_rect() + + self:draw_border() + self:draw_scrollbar() + + return true +end + + +return ListBox diff --git a/debian/extra/libraries/widget/messagebox.lua b/debian/extra/libraries/widget/messagebox.lua new file mode 100644 index 0000000..4a089a1 --- /dev/null +++ b/debian/extra/libraries/widget/messagebox.lua @@ -0,0 +1,343 @@ +-- +-- MessageBox Widget/Dialog. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local core = require "core" +local common = require "core.common" +local style = require "core.style" +local Widget = require "libraries.widget" +local Button = require "libraries.widget.button" +local Label = require "libraries.widget.label" + +---@class widget.messagebox : widget +---@overload fun(parent?:widget, title?:string, message?:string|widget.styledtext, icon?:widget.messagebox.icontype, icon_color?:renderer.color):widget.messagebox +---@field private title widget.label +---@field private icon widget.label +---@field private message widget.label +---@field private buttons widget.button[] +local MessageBox = Widget:extend() + +MessageBox.icon_huge_font = style.icon_font:copy(50 * SCALE) + +MessageBox.ICON_ERROR = "X" +MessageBox.ICON_INFO = "i" +MessageBox.ICON_WARNING = "!" + +---@alias widget.messagebox.icontype +---|>`MessageBox.ICON_ERROR` +---| `MessageBox.ICON_INFO` +---| `MessageBox.ICON_WARNING` + +MessageBox.BUTTONS_OK = 1 +MessageBox.BUTTONS_OK_CANCEL = 2 +MessageBox.BUTTONS_YES_NO = 3 +MessageBox.BUTTONS_YES_NO_CANCEL = 4 + +---@alias widget.messagebox.buttonstype +---|>`MessageBox.BUTTONS_OK` +---| `MessageBox.BUTTONS_OK_CANCEL` +---| `MessageBox.BUTTONS_YES_NO` +---| `MessageBox.BUTTONS_YES_NO_CANCEL` + +---@alias widget.messagebox.onclosehandler fun(self: widget.messagebox, button_id: integer, button: widget.button) + +---Constructor +---@param parent widget +---@param title string +---@param message string | widget.styledtext +---@param icon widget.messagebox.icontype +---@param icon_color renderer.color +function MessageBox:new(parent, title, message, icon, icon_color) + MessageBox.super.new(self, parent) + self.type_name = "widget.messagebox" + self.draggable = true + self.scrollable = true + self.title = Label(self, "") + self.icon = Label(self, "") + self.message = Label(self, "") + self.buttons = {} + self.last_scale = SCALE + + self:set_title(title or "") + self:set_message(message or "") + self:set_icon(icon or "", icon_color) +end + +---Change the message box title. +---@param text string | widget.styledtext +function MessageBox:set_title(text) + self.title:set_label(text) +end + +---Change the message box icon. +---@param icon widget.messagebox.icontype +---@param color? renderer.color +function MessageBox:set_icon(icon, color) + if not color then + color = style.text + if icon == MessageBox.ICON_WARNING then + color = { common.color "#c7763e" } + elseif icon == MessageBox.ICON_ERROR then + color = { common.color "#c73e3e" } + end + end + self.icon:set_label({ MessageBox.icon_huge_font, color, icon }) +end + +---Change the message box message. +---@param text string | widget.styledtext +function MessageBox:set_message(text) + self.message:set_label(text) +end + +---Adds a new button to the message box. +---@param button_or_label string|widget.button +function MessageBox:add_button(button_or_label) + if type(button_or_label) == "table" then + table.insert(self.buttons, button_or_label) + else + local button = Button(self, button_or_label) + table.insert(self.buttons, button) + end + + local button_id = #self.buttons + local new_button = self.buttons[button_id] + local on_click = new_button.on_click + new_button.on_click = function(this, ...) + on_click(this, ...) + self:on_close(button_id, new_button) + end +end + +---Calculate the width of all buttons combined. +---@return number width +function MessageBox:get_buttons_width() + local width = 0 + if #self.buttons > 0 then + for _, button in ipairs(self.buttons) do + width = width + button:get_width() + end + -- add padding inbetween buttons + if #self.buttons > 1 then + width = width + ((style.padding.x) * (#self.buttons - 1)) + end + end + return width +end + +---Get the height of biggest button. +---@return number height +function MessageBox:get_buttons_height() + local height = 0 + if #self.buttons > 0 then + for _, button in ipairs(self.buttons) do + height = math.max(height, button:get_height()) + end + end + return height +end + +---Position the buttons relative to the message. +function MessageBox:reposition_buttons() + local buttons_width = self:get_buttons_width() + local buttons_x = ((self.size.x / 2) - (buttons_width / 2)) + local buttons_y = self.message:get_bottom() + (style.padding.y * 2) + if self.icon.label[3] ~= "" then + buttons_y = math.max( + buttons_y, self.icon:get_bottom() + (style.padding.y * 2) + ) + end + + for _, button in ipairs(self.buttons) do + button:set_position(buttons_x, buttons_y) + buttons_x = buttons_x + button:get_width() + style.padding.x + end +end + +---Calculate the MessageBox size, centers it relative to screen and shows it. +function MessageBox:show() + MessageBox.super.show(self) + self:update() + self:centered() +end + +---Called when the user clicks one of the buttons in the message box. +---@param button_id integer +---@param button widget.button +---@diagnostic disable-next-line +function MessageBox:on_close(button_id, button) self:hide() end + +function MessageBox:update() + if not MessageBox.super.update(self) then return false end + + if self.last_scale ~= SCALE then + MessageBox.icon_huge_font = style.icon_font:copy(50 * SCALE) + self.last_scale = SCALE + self.icon.label[1] = MessageBox.icon_huge_font + elseif self.updated then + self.updated = true + return + end + + local width = math.max(self.title:get_width()) + width = math.max(width, self.message:get_width() + self.icon:get_width()) + width = math.max(width, self:get_buttons_width()) + + local height = self.title:get_height() + style.padding.y + if self.icon.label[3] == "" then + height = height + self.message:get_height() + (style.padding.y * 2) + else + height = height + + math.max(self.icon:get_height(), self.message:get_height()) + + (style.padding.y * 2) + end + height = height + self:get_buttons_height() + + self:set_size(width + style.padding.x * 2, height + style.padding.y * 2) + + self.title:set_position( + style.padding.x / 2, + style.padding.y / 2 + ) + + self.icon:set_position( + style.padding.x, + self.title:get_bottom() + style.padding.y + ) + + if self.icon.label[3] == "" then + self.message:set_position( + style.padding.x, + self.title:get_bottom() + style.padding.y + ) + else + local msg_y = self.title:get_bottom() + style.padding.y + 10 + if self.icon:get_height() > self.message:get_height() then + msg_y = (self.icon:get_height() / 2) + - (self.message:get_height() / 2) + + self.title:get_bottom() + style.padding.y + end + self.message:set_position( + self.icon:get_width() + (style.padding.x * 2) - (style.padding.x / 2), + msg_y + ) + end + + self:reposition_buttons() + + return true +end + +---We overwrite default draw function to draw the title background. +function MessageBox:draw() + if not self:is_visible() then return false end + + Widget.super.draw(self) + + self:draw_border() + + if self.background_color then + self:draw_background(self.background_color) + else + self:draw_background( + self.parent and style.background or style.background2 + ) + end + + if #self.childs > 0 then + core.push_clip_rect( + self.position.x, + self.position.y, + self.size.x, + self.size.y + ) + end + + -- draw the title background + renderer.draw_rect( + self.position.x, + self.position.y, + self.size.x, self.title:get_height() + style.padding.y, + style.selection + ) + + for i=#self.childs, 1, -1 do + self.childs[i]:draw() + end + + if #self.childs > 0 then + core.pop_clip_rect() + end + + self:draw_scrollbar() + + return true +end + +---Wrapper to easily show a message box. +---@param title string | widget.styledtext +---@param message string | widget.styledtext +---@param icon widget.messagebox.icontype +---@param icon_color? renderer.color +---@param on_close? widget.messagebox.onclosehandler +---@param buttons? widget.messagebox.buttonstype +function MessageBox.alert(title, message, icon, icon_color, on_close, buttons) + buttons = buttons or MessageBox.BUTTONS_OK + ---@type widget.messagebox + local msgbox = MessageBox(nil, title, message, icon, icon_color) + if buttons == MessageBox.BUTTONS_OK_CANCEL then + msgbox:add_button("Ok") + msgbox:add_button("Cancel") + elseif buttons == MessageBox.BUTTONS_YES_NO then + msgbox:add_button("Yes") + msgbox:add_button("No") + elseif buttons == MessageBox.BUTTONS_YES_NO_CANCEL then + msgbox:add_button("Yes") + msgbox:add_button("No") + msgbox:add_button("Cancel") + else + msgbox:add_button("Ok") + end + + local msgbox_on_close = msgbox.on_close + msgbox.on_close = function(self, button_id, button) + if on_close then + on_close(self, button_id, button) + end + msgbox_on_close(self, button_id, button) + self:destroy() + end + msgbox:show() +end + +---Wrapper to easily show a info message box. +---@param title string | widget.styledtext +---@param message string | widget.styledtext +---@param on_close? widget.messagebox.onclosehandler +---@param buttons? widget.messagebox.buttonstype +function MessageBox.info(title, message, on_close, buttons) + MessageBox.alert(title, message, MessageBox.ICON_INFO, nil, on_close, buttons) +end + +---Wrapper to easily show a warning message box. +---@param title string | widget.styledtext +---@param message string | widget.styledtext +---@param on_close? widget.messagebox.onclosehandler +---@param buttons? widget.messagebox.buttonstype +function MessageBox.warning(title, message, on_close, buttons) + MessageBox.alert(title, message, MessageBox.ICON_WARNING, nil, on_close, buttons) +end + +---Wrapper to easily show an error message box. +---@param title string | widget.styledtext +---@param message string | widget.styledtext +---@param on_close? widget.messagebox.onclosehandler +---@param buttons? widget.messagebox.buttonstype +function MessageBox.error(title, message, on_close, buttons) + MessageBox.alert(title, message, MessageBox.ICON_ERROR, nil, on_close, buttons) +end + + +return MessageBox diff --git a/debian/extra/libraries/widget/notebook.lua b/debian/extra/libraries/widget/notebook.lua new file mode 100644 index 0000000..1b64a42 --- /dev/null +++ b/debian/extra/libraries/widget/notebook.lua @@ -0,0 +1,188 @@ +-- +-- NoteBook Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local style = require "core.style" +local Widget = require "libraries.widget" +local Button = require "libraries.widget.button" + +local HSPACING = 2 +local VSPACING = 2 + +---Represents a notebook pane +---@class widget.notebook.pane +---@field public name string +---@field public tab widget.button +---@field public container widget +local NoteBookPane = {} + +---@class widget.notebook : widget +---@overload fun(parent?:widget):widget.notebook +---@field public panes widget.notebook.pane[] +---@field public active_pane widget.notebook.pane +local NoteBook = Widget:extend() + +---Notebook constructor +---@param parent widget +function NoteBook:new(parent) + NoteBook.super.new(self, parent) + self.type_name = "widget.notebook" + self.panes = {} + self.active_pane = nil +end + +---Called when a tab is clicked. +---@param pane widget.notebook.pane +---@diagnostic disable-next-line +function NoteBook:on_tab_click(pane) end + +---Adds a new pane to the notebook and returns a container widget where +---you can add more child elements. +---@param name string +---@param label string +---@return widget container +function NoteBook:add_pane(name, label) + ---@type widget.button + local tab = Button(self, label) + tab.border.width = 0 + + if #self.panes > 0 then + tab:set_position(self.panes[#self.panes].tab:get_right() + HSPACING, 0) + end + + local container = Widget(self) + container.scrollable = true + container:set_position(0, tab:get_bottom() + VSPACING) + container:set_size( + self:get_width(), + self:get_height() - tab:get_height() - VSPACING + ) + + local pane = { + name = name, + tab = tab, + container = container + } + + if not self.active_pane then + self.active_pane = pane + end + + tab.on_click = function() + self.active_pane = pane + self:on_tab_click(pane) + end + + table.insert(self.panes, pane) + + return container +end + +---Search the pane for the given name and return it. +---@param name string +---@return widget.notebook.pane | nil +function NoteBook:get_pane(name) + for _, pane in pairs(self.panes) do + if pane.name == name then + return pane + end + end + return nil +end + +---Activates the given pane. +---@param name string +---@return boolean +function NoteBook:set_pane(name) + local pane = self:get_pane(name) + if pane then + self.active_pane = pane + return true + end + return false +end + +---Change the tab label of the given pane. +---@param name string +---@param label string +function NoteBook:set_pane_label(name, label) + local pane = self:get_pane(name) + if pane then + pane.tab:set_label(label) + return true + end + return false +end + +---Set or remove the icon for the given pane. +---@param name string +---@param icon? string|nil +---@param color? renderer.color|nil +---@param hover_color? renderer.color|nil +function NoteBook:set_pane_icon(name, icon, color, hover_color) + local pane = self:get_pane(name) + if pane then + pane.tab:set_icon(icon, color, hover_color) + return true + end + return false +end + +---Recalculate the position of the elements on resizing or position +---changes and also make changes to properly render active pane. +function NoteBook:update() + if not NoteBook.super.update(self) then return false end + + for pos, pane in pairs(self.panes) do + if pos ~= 1 then + pane.tab:set_position( + self.panes[pos-1].tab:get_right() + HSPACING, 0 + ) + else + pane.tab:set_position(0, 0) + end + if pane ~= self.active_pane then + if pane.container.visible then + pane.tab.background_color = style.background + pane.tab.foreground_color = style.text + pane.container:hide() + end + elseif not pane.container.visible then + pane.container:show() + end + end + + if self.active_pane then + self.active_pane.tab.foreground_color = style.accent + + self.active_pane.container:set_position( + 0, self.active_pane.tab:get_bottom() + VSPACING + ) + self.active_pane.container:set_size( + self:get_width(), + self:get_height() - self.active_pane.tab:get_height() - VSPACING + ) + self.active_pane.container.border.color = style.divider + end + + return true +end + +---Here we draw the bottom line on the tab of active pane. +function NoteBook:draw() + if not NoteBook.super.draw(self) then return false end + + if self.active_pane then + local x = self.active_pane.tab.position.x + local y = self.active_pane.tab.position.y + self.active_pane.tab:get_bottom() + local w = self.active_pane.tab:get_width() + renderer.draw_rect(x, y, w, HSPACING, style.caret) + end + + return true +end + + +return NoteBook diff --git a/debian/extra/libraries/widget/numberbox.lua b/debian/extra/libraries/widget/numberbox.lua new file mode 100644 index 0000000..31f885c --- /dev/null +++ b/debian/extra/libraries/widget/numberbox.lua @@ -0,0 +1,238 @@ +-- +-- NumberBox Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local core = require "core" +local Widget = require "libraries.widget" +local Button = require "libraries.widget.button" +local TextBox = require "libraries.widget.textbox" + +---@class widget.numberbox : widget +---@overload fun(parent?:widget, value:number, min?:number, max?:number, step?:number):widget.numberbox +---@field private textbox widget.textbox +---@field private decrease_button widget.button +---@field private increase_button widget.button +---@field private minimum number +---@field private maximum number +---@field private step number +local NumberBox = Widget:extend() + +---Constructor +---@param parent widget +---@param value number +---@param min? number +---@param max? number +---@param step? number +function NumberBox:new(parent, value, min, max, step) + NumberBox.super.new(self, parent) + + self.type_name = "widget.numberbox" + + self:set_range(min, max) + self:set_step(step) + + self.textbox = TextBox(self, "") + self.textbox.scrollable = true + + self.decrease_button = Button(self, "-") + self.increase_button = Button(self, "+") + + self:set_value(value) + + local this = self + function self.textbox.textview.doc:on_text_change(type) + if not tonumber(this.textbox:get_text()) then + if not this.coroutine_run then + this.coroutine_run = true + core.add_thread(function() + this.textbox:set_text(this.current_text) + this.coroutine_run = false + end) + end + else + this.textbox.placeholder_active = false + this.current_text = this.textbox:get_text() + this:on_change(tonumber(this.current_text)) + end + end + function self.textbox:on_mouse_wheel(y) + if self.active then + if y > 0 then this:increase() else this:decrease() end + return true + end + return false + end + function self.decrease_button:on_mouse_pressed(button, x, y, clicks) + if Button.super.on_mouse_pressed(self, button, x, y, clicks) then + this.mouse_is_pressed = true + this:mouse_pressed(false) + return true + end + return false + end + function self.increase_button:on_mouse_pressed(button, x, y, clicks) + if Button.super.on_mouse_pressed(self, button, x, y, clicks) then + this.mouse_is_pressed = true + this:mouse_pressed(true) + return true + end + return false + end + function self.decrease_button:on_mouse_released(button, x, y) + if Button.super.on_mouse_released(self, button, x, y) then + this.mouse_is_pressed = false + return true + end + return false + end + function self.increase_button:on_mouse_released(button, x, y) + if Button.super.on_mouse_released(self, button, x, y) then + this.mouse_is_pressed = false + return true + end + return false + end + + self.border.width = 0 + + self:set_size( + self.textbox:get_width() - 100 + + self.decrease_button:get_width() + + self.increase_button:get_width() + ) +end + +---Set a new value. +---@param value number +function NumberBox:set_value(value) + if type(value) == "number" then + self.textbox:set_text(tostring(value)) + elseif type(value) == "string" and tonumber(value) then + self.textbox:set_text(value) + else + self.textbox:set_text(tostring(self.minimum)) + end + self.textbox.placeholder_active = false + self.current_text = self.textbox:get_text() + self:on_change(tonumber(self.current_text)) +end + +---Get the current value. +---@return number +function NumberBox:get_value() + return tonumber(self.textbox:get_text()) or self.minimum +end + +---Set the minimum and maximum values allowed. +---@param min? number +---@param max? number +function NumberBox:set_range(min, max) + self.minimum = min or math.mininteger + self.maximum = max or math.maxinteger +end + +---Set the value used to increase or decrease the number when the +---buttons are pressed. +---@param step number +function NumberBox:set_step(step) + self.step = step or 1 +end + +---Decrease the current value. +function NumberBox:decrease() + self.textbox.placeholder_active = false + local value = tonumber(self.textbox:get_text()) or self.maximum + if (value - self.step) >= self.minimum then + self:set_value(value - self.step) + end +end + +---Increase the current value. +function NumberBox:increase() + self.textbox.placeholder_active = false + local value = tonumber(self.textbox:get_text()) or self.minimum + if (value + self.step) <= self.maximum then + self:set_value(value + self.step) + end +end + +---Triggered when the mouse is pressed on the increase/decrease buttons. +---@param increase boolean +function NumberBox:mouse_pressed(increase) + if increase then self:increase() else self:decrease() end + + local elapsed = system.get_time() + 0.3 + local this = self + + core.add_thread(function() + while this.mouse_is_pressed do + if elapsed < system.get_time() then + if increase then + this:increase() + else + this:decrease() + end + core.redraw = true + elapsed = system.get_time() + 0.1 + end + coroutine.yield() + end + end) +end + +---Overrided to enforce minimum allowed size. +---@param width integer +---@param height? integer Ignored on the number box +function NumberBox:set_size(width, height) + local buttons_w = self.decrease_button:get_width() + + self.increase_button:get_width() + + -- permit a minimum of 100 pixels wide for textbox + if width < (buttons_w + 100) then + width = 100 + buttons_w + end + + self.textbox:set_size(width - buttons_w) + + NumberBox.super.set_size( + self, + width, + math.max( + self.textbox:get_height(), + self.decrease_button:get_height(), + self.increase_button:get_height() + ) + -- TODO: check what causes the need for this border size addition since + -- it shouldn't be needed but for now fixes occasional bottom border cut. + + self.increase_button.border.width + ) +end + +function NumberBox:update() + if not NumberBox.super.update(self) then return false end + + self:set_size( + self.textbox:get_width() + + self.decrease_button:get_width() + + self.increase_button:get_width() + ) + + self.textbox:set_position(0, 0) + + self.decrease_button:set_position( + self.textbox:get_right(), + 0 + ) + + self.increase_button:set_position( + self.decrease_button:get_right(), + 0 + ) + + return true +end + + +return NumberBox diff --git a/debian/extra/libraries/widget/progressbar.lua b/debian/extra/libraries/widget/progressbar.lua new file mode 100644 index 0000000..5c88036 --- /dev/null +++ b/debian/extra/libraries/widget/progressbar.lua @@ -0,0 +1,95 @@ +-- +-- ProgressBar Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local style = require "core.style" +local Widget = require "libraries.widget" + +---@class widget.progressbar : widget +---@overload fun(parent?:widget, percent?:number, width?:number):widget.progressbar +---@field public percent number +---@field public show_percent boolean +---@field private percent_width number +---@field private percent_x number +---@field private percent_y number +local ProgressBar = Widget:extend() + +---Constructor +---@param parent widget +---@param percent number +---@param width number +function ProgressBar:new(parent, percent, width) + ProgressBar.super.new(self, parent) + self.type_name = "widget.progressbar" + self.clickable = false + self.percent = percent or 0 + self.percent_width = 0 + self.show_percent = true + self:set_size(width or 200, self:get_font():get_height() + style.padding.y) +end + +---@param percent number +function ProgressBar:set_percent(percent) + self.percent = percent +end + +---@return number +function ProgressBar:get_percent() + return self.percent +end + +function ProgressBar:update() + if not ProgressBar.super.update(self) then return false end + + local font = self:get_font() + + -- update the size + self:set_label(self.percent .. "%") + + self:set_size( + nil, + font:get_height() + style.padding.y + ) + + local percent_width = (self.size.x * (self.percent / 100)) + + self:move_towards(self, "percent_width", percent_width, 0.2) + + if self.show_percent then + self.percent_x = (self:get_width() / 2) + - (font:get_width(self.label) / 2) + + self.percent_y = style.padding.y / 2 + end + + return true +end + +function ProgressBar:draw() + if not ProgressBar.super.draw(self) then return false end + + renderer.draw_rect( + self.position.x, + self.position.y, + self.percent_width, + self.size.y, + style.dim + ) + + if self.show_percent then + renderer.draw_text( + self:get_font(), + self.label, + self.position.x + self.percent_x, + self.position.y + self.percent_y, + style.text + ) + end + + return true +end + + +return ProgressBar diff --git a/debian/extra/libraries/widget/scrollbar.lua b/debian/extra/libraries/widget/scrollbar.lua new file mode 100644 index 0000000..5f9c181 --- /dev/null +++ b/debian/extra/libraries/widget/scrollbar.lua @@ -0,0 +1,33 @@ +-- +-- Extends core.scrollbar to allow propagating force status to child elements. +-- + +---@type core.scrollbar +local CoreScrollBar = require "core.scrollbar" + +---@class widget.scrollbar : core.scrollbar +---@overload fun(parent?:widget, options?:table):widget.scrollbar +---@field super widget.scrollbar +---@field widget_parent widget +local ScrollBar = CoreScrollBar:extend() + +function ScrollBar:new(parent, options) + self.widget_parent = parent + ScrollBar.super.new(self, options) +end + +function ScrollBar:set_forced_status(status) + ScrollBar.super.set_forced_status(self, status) + if self.widget_parent and self.widget_parent.childs then + for _, child in pairs(self.widget_parent.childs) do + if self.direction == "v" then + child.v_scrollbar:set_forced_status(status) + else + child.h_scrollbar:set_forced_status(status) + end + end + end +end + + +return ScrollBar diff --git a/debian/extra/libraries/widget/searchreplacelist.lua b/debian/extra/libraries/widget/searchreplacelist.lua new file mode 100644 index 0000000..0f5db33 --- /dev/null +++ b/debian/extra/libraries/widget/searchreplacelist.lua @@ -0,0 +1,607 @@ +-- +-- SearchReplaceList Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local core = require "core" +local common = require "core.common" +local style = require "core.style" +local Widget = require "libraries.widget" + +---@class widget.searchreplacelist.lineposition +---@field col1 integer +---@field col2 integer +---@field checked boolean? + +---@class widget.searchreplacelist.line +---@field line integer +---@field text string +---@field positions widget.searchreplacelist.lineposition[] + +---@class widget.searchreplacelist.file +---@field path string +---@field lines widget.searchreplacelist.line[] +---@field expanded boolean + +---@class widget.searchreplacelist.item +---@field checked boolean +---@field file widget.searchreplacelist.file? +---@field parent widget.searchreplacelist.item? +---@field line widget.searchreplacelist.line? +---@field position widget.searchreplacelist.lineposition? + +---@class widget.searchreplacelist : widget +---@field replacement string? +---@field selected integer +---@field hovered integer +---@field items widget.searchreplacelist.item[] +---@field total_files integer +---@field total_results integer +---@field base_dir string +---@overload fun(parent:widget, find:string, replacement:string?):widget.searchreplacelist +local SearchReplaceList = Widget:extend() + +---Colors to use when performing a replacement. +local DIFF = { + ADD = { common.color "#72b886" }, + DEL = { common.color "#F36161" }, + TEXT = { common.color "#000000" } +} + +---Constructor +---@param parent widget +---@param replacement string? +function SearchReplaceList:new(parent, replacement) + SearchReplaceList.super.new(self, parent) + + self.type_name = "widget.searchreplacelist" + + self.replacement = replacement or nil + self.selected = 0 + self.hovered = 0 + self.items = {} + self.max_width = 0 + self.hovered_checkbox = false + self.hovered_expander = false + self.scrollable = true + self.total_files = 0 + self.total_results = 0 + self.base_dir = "" +end + +---Overridable event triggered when an item is clicked. +---@param item widget.searchreplacelist.item +---@param clicks integer +function SearchReplaceList:on_item_click(item, clicks) end + +---Add a new file with all the matching lines and positions. +---@param path string +---@param lines widget.searchreplacelist.line[] +---@param expanded boolean? +function SearchReplaceList:add_file(path, lines, expanded) + if type(expanded) == "nil" then expanded = true end + table.insert(self.items, { + checked = true, + file = { + path = path, + lines = lines, + expanded = false + } + }) + self.total_files = self.total_files + 1 + -- expand results and count them + if expanded and #lines > 0 then + self:expand(#self.items, true) + -- count the results only + else + for _, line in ipairs(self.items[#self.items]) do + self.total_results = self.total_results + #line.positions + end + end +end + +---Removes all elements from the list and reset it. +function SearchReplaceList:clear() + self.selected = 0 + self.hovered = 0 + self.items = {} + self.max_width = 0 + self.hovered_checkbox = false + self.hovered_expander = false + self.total_files = 0 + self.total_results = 0 +end + +---Uncollapse a file line results. +---@param position integer +function SearchReplaceList:expand(position, count_results) + local parent = self.items[position] + if + parent and parent.file + and + not parent.file.expanded + then + local insert_pos = position+1 + local items = {} + for _, line in ipairs(parent.file.lines) do + for _, line_pos in ipairs(line.positions) do + table.insert(items, { + parent = parent, + line = line, + position = line_pos + }) + if count_results then + self.total_results = self.total_results + 1 + end + end + end + common.splice(self.items, insert_pos, 0, items) + parent.file.expanded = true + end +end + +---Collapse a file line results. +---@param position integer +function SearchReplaceList:contract(position) + local parent = self.items[position] + if + parent and parent.file + and + parent.file.expanded + then + local start_pos = position+1 + local end_pos = 0 + for _, line in ipairs(parent.file.lines) do + for _, _ in ipairs(line.positions) do + end_pos = end_pos + 1 + end + end + common.splice(self.items, start_pos, end_pos) + parent.file.expanded = false + end +end + +---Collapse/uncollapse a file line results. +---@param position integer +function SearchReplaceList:toggle_expand(position) + local parent = self.items[position] + if parent and parent.file then + if parent.file.expanded then + self:contract(position) + else + self:expand(position) + end + end +end + +---Toggle the checkbox of the given item position. +---@param pos integer +function SearchReplaceList:toggle_check(pos) + local item = self.items[pos] + if not item or self.replacement == nil then return end + if item.file then + item.checked = not item.checked + for _, line in ipairs(item.file.lines) do + for _, position in ipairs(line.positions) do + position.checked = item.checked + end + end + else + if type(item.position.checked) == "nil" then + item.position.checked = false + else + item.position.checked = not item.position.checked + end + local parent_checked = true + for _, line in ipairs(item.parent.file.lines) do + for _, position in ipairs(line.positions) do + if position.checked == false then + parent_checked = false + break + end + end + end + item.parent.checked = parent_checked + end +end + +---Replace a position on a string with a given replacement. +---@param str string +---@param s integer +---@param e integer +---@param rep string +local function replace_substring(str, s, e, rep) + local head = s <= 1 and "" or string.sub(str, 1, s - 1) + local tail = e >= #str and "" or string.sub(str, e + 1) + return head .. rep .. tail +end + +---Applies the replacement on the given item position but not on the real file. +--- +---The purpose of this function is to reflect the changes on the listed items. +---@param position integer +function SearchReplaceList:apply_replacement(position) + local item = self.items[position] + if item and item.file and self.replacement then + local replacement = self.replacement + local replacement_len = #self.replacement + for _, line in ipairs(item.file.lines) do + local offset = 0 + for _, pos in ipairs(line.positions) do + local col1 = pos.col1 + offset + local col2 = pos.col2 + offset + if pos.checked or type(pos.checked) == "nil" then + line.text = replace_substring(line.text, col1, col2, replacement) + local current_len = col2 - col1 + 1 + local len_diff = 0 + if current_len > replacement_len then + len_diff = current_len - replacement_len + offset = offset - len_diff + col2 = col2 - len_diff + elseif current_len < replacement_len then + len_diff = replacement_len - current_len + offset = offset + len_diff + col2 = col2 + len_diff + end + end + pos.col1, pos.col2 = col1, col2 + end + end + end +end + +---Select the item that follows currently selected item. +---@return widget.searchreplacelist.item? +function SearchReplaceList:select_next() + local items_count = #self.items + if items_count <= 0 then return nil end + local selected = self.selected+1 + if selected > items_count then selected = 1 end + self.selected = common.clamp(selected, 1, items_count) + self:scroll_to_selected() + return self.items[self.selected] +end + +---Select the item that precedes currently selected item. +---@return widget.searchreplacelist.item? +function SearchReplaceList:select_prev() + local items_count = #self.items + if items_count <= 0 then return nil end + local selected = self.selected-1 + if selected < 1 then selected = items_count end + self.selected = common.clamp(selected, 1, items_count) + self:scroll_to_selected() + return self.items[self.selected] +end + +---Get the currently selected item. +---@return widget.searchreplacelist.item? +function SearchReplaceList:get_selected() + if self.selected > 0 and self.selected <= #self.items then + return self.items[self.selected] + end + return nil +end + +---Get the line height used when drawing each item row. +---@return number height +function SearchReplaceList:get_line_height() + return style.padding.y + style.font:get_height() +end + +---Used when calculating if vertical scrolling is needed. +---@return number size +function SearchReplaceList:get_scrollable_size() + return #self.items * self:get_line_height() + style.padding.y +end + +---Used when calculating if horizontal scrolling is needed. +---@return number size +function SearchReplaceList:get_h_scrollable_size() + local width = style.padding.x / 2 + + style.icon_font:get_width("-") + + style.padding.x / 2 + + self.max_width + if self.replacement then + local cb_w = self:get_checkbox_size() + width = width + + cb_w + style.padding.x / 2 + + style.font:get_width(self.replacement) + end + return width +end + +---Get the checkbox size based on the line height. +---@param y? number +---@return number w +---@return number h +---@return number y Vertically center align coord based on given y param +function SearchReplaceList:get_checkbox_size(y) + if not y then y = 0 end + local lh = self:get_line_height() + local w = lh * 0.6 + local h = w + y = y + ((lh / 2) - (h / 2)) + return w, h, y +end + +---Get the position of first and last visible items. +---@return integer first +---@return integer last +function SearchReplaceList:get_visible_items_range() + local lh = self:get_line_height() + local min = math.max(1, math.floor(self.scroll.y / lh)) + return min, min + math.floor(self.size.y / lh) + 1 +end + +---Allows iterating the currently visible items only. +---@return fun():integer,widget.searchreplacelist.item,number,number,number,number +function SearchReplaceList:each_visible_item() + return coroutine.wrap(function() + local lh = self:get_line_height() + local x, y = self:get_content_offset() + local min, max = self:get_visible_items_range() + y = y + lh * (min - 1) + for i = min, max do + local item = self.items[i] + if not item then break end + coroutine.yield(i, item, x, y, self.size.x, lh) + y = y + lh + end + end) +end + +---Iterates over all files, only those that have a position checked on replacement mode. +---@return fun():integer,widget.searchreplacelist.file +function SearchReplaceList:each_file() + return coroutine.wrap(function() + local replacement = self.replacement + for i, item in ipairs(self.items) do + if item.file then + if replacement then + local none_checked = true + for _, line in ipairs(item.file.lines) do + for _, pos in ipairs(line.positions) do + if type(pos.checked) == "nil" or pos.checked then + none_checked = false + break + end + end + end + if none_checked then + goto continue + end + end + coroutine.yield(i, item.file) + end + ::continue:: + end + end) +end + +---Scroll to currently selected item only if not already visible. +function SearchReplaceList:scroll_to_selected() + if self.selected == 0 then return end + local h = self:get_line_height() + local y = h * (self.selected - 1) + self.scroll.to.y = math.min(self.scroll.to.y, y) + self.scroll.to.y = math.max(self.scroll.to.y, y + h - self.size.y) +end + +function SearchReplaceList:on_mouse_moved(mx, my, ...) + if not SearchReplaceList.super.on_mouse_moved(self, mx, my, ...) then + return false + end + self.hovered = 0 + for i, item, x,y,w,h in self:each_visible_item() do + w = self.size.x + if mx >= x and my >= y and mx < x + w and my < y + h then + self.hovered = i + x = x + style.padding.x / 2 + w = style.icon_font:get_width('-') + if item.file and mx >= x and my >= y and mx < x + w and my < y + h then + self.hovered_expander = true + self.hovered_checkbox = false + else + self.hovered_expander = false + end + if not self.hovered_expander and self.replacement then + x = x + w + style.padding.x / 2 + w, h, y = self:get_checkbox_size(y) + if mx >= x and my >= y and mx < x + w and my < y + h then + self.hovered_checkbox = true + self.hovered_expander = false + else + self.hovered_checkbox = false + end + end + break + end + end + return true +end + +function SearchReplaceList:on_mouse_pressed(button, x, y, clicks) + if + not SearchReplaceList.super.on_mouse_pressed(self, button, x, y, clicks) + then + return false + end + if self:scrollbar_hovering() then return true end + local item = self.items[self.hovered] + if not item then return true end + self.selected = self.hovered + if self.hovered_checkbox then + self:toggle_check(self.selected) + elseif item.file and (clicks > 1 or self.hovered_expander) then + if not item.file.expanded then + self:expand(self.hovered) + else + self:contract(self.hovered) + end + else + self:on_item_click(item, clicks) + end + return true +end + +function SearchReplaceList:draw_checkbox(checked, hovered, x, y, lh) + local w, h, cy = self:get_checkbox_size(y) + renderer.draw_rect(x, cy, w, h, style.text) + renderer.draw_rect( + x + 2, cy + 2, w-4, h-4, + hovered and style.dim or style.background + ) + if checked then + renderer.draw_rect(x + 5, cy + 5, w-10, h-10, style.caret) + end + return x + w +end + +function SearchReplaceList:draw() + if not SearchReplaceList.super.draw(self) then return false end + + core.push_clip_rect( + self.position.x, + self.position.y, + self.size.x, + self.size.y + ) + + local font = self:get_font() + + local replacement = self.replacement + local replacement_width = font:get_width(replacement or "") + local file_path + + self.max_width = 0 + + for i, item, x,y,w,h in self:each_visible_item() do + if item.file then + file_path = common.relative_path(self.base_dir, item.file.path) + end + + -- add left padding + x = x + style.padding.x / 2 + + local text_color = style.text + + if i == self.selected then + renderer.draw_rect(self.position.x, y, self.size.x, h, style.selection) + elseif i == self.hovered then + renderer.draw_rect(self.position.x, y, self.size.x, h, style.line_highlight) + text_color = style.accent + end + + -- draw collapse/contract symbol + if item.file then + common.draw_text( + style.icon_font, + (self.hovered == i and self.hovered_expander) and style.accent or style.text, + item.file.expanded and "-" or "+", + "left", + x, y, w, h + ) + x = x + style.icon_font:get_width("-") + else + x = x + style.icon_font:get_width("-") + end + + x = x + style.padding.x / 2 + + -- draw checkbox + if replacement then + local checked = false + if item.file then + checked = item.checked + else + if type(item.position.checked) == "nil" then + checked = true + else + checked = item.position.checked + end + end + x = style.padding.x / 2 + self:draw_checkbox( + checked, + i == self.hovered and self.hovered_checkbox or false, + x, y, h + ) + end + + -- draw text + local text = item.file and file_path or item.line.text + local all_text = "" + + if item.line then + local start_pos, end_pos = 1, #text + local prefix, postfix = "", "" + -- truncate long lines to keep good rendering performance + if #text > 120 then + start_pos = math.max(item.position.col1 - 50, 1) + end_pos = math.min(item.position.col2 + 50, end_pos) + if start_pos ~= 1 then prefix = "..." end + if end_pos ~= #text then postfix = "..." end + end + x = common.draw_text( + font, + style.syntax["number"], + tostring(item.line.line) .. ": ", + "left", + x, y, w, h + ) + local start_text = item.position.col1 ~= 1 and + prefix .. text:sub(start_pos, item.position.col1-1) + or + "" + local end_text = item.position.col2 ~= #text and + text:sub(item.position.col2+1, end_pos) .. postfix + or + "" + local found_text = text:sub(item.position.col1, item.position.col2) + local found_width = style.font:get_width(found_text) + if start_text ~= "" then + x = common.draw_text( + font, + text_color, + start_text, + "left", + x, y, w, h + ) + end + local found_color = not replacement and style.dim or DIFF.DEL + local found_text_color = not replacement and text_color or DIFF.TEXT + renderer.draw_rect(x, y, found_width, h, found_color) + x = common.draw_text(font, found_text_color, found_text, "left", x, y, w, h) + if replacement then + renderer.draw_rect(x, y, replacement_width, h, DIFF.ADD) + x = common.draw_text(font, DIFF.TEXT, replacement, "left", x, y, w, h) + end + if end_text ~= "" then + x = common.draw_text( + font, + text_color, + end_text, + "left", + x, y, w, h + ) + end + all_text = item.line.line .. ": " .. start_text .. found_text .. end_text + else + x = common.draw_text(font, text_color, text, "left", x, y, w, h) + all_text = file_path + end + + -- recalc max_width for horizontal scrollbar + self.max_width = math.max(self.max_width, style.font:get_width(all_text)) + end + + core.pop_clip_rect() + + self:draw_scrollbar() + + return true +end + + +return SearchReplaceList diff --git a/debian/extra/libraries/widget/selectbox.lua b/debian/extra/libraries/widget/selectbox.lua new file mode 100644 index 0000000..45314c8 --- /dev/null +++ b/debian/extra/libraries/widget/selectbox.lua @@ -0,0 +1,288 @@ +-- +-- SelectBox Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local core = require "core" +local common = require "core.common" +local style = require "core.style" +local Widget = require "libraries.widget" +local ListBox = require "libraries.widget.listbox" + +---@class widget.selectbox : widget +---@overload fun(parent?:widget, label?:string):widget.selectbox +---@field private list_container widget +---@field private list widget.listbox +---@field private selected integer +---@field private hover_text renderer.color +local SelectBox = Widget:extend() + +---Constructor +---@param parent widget +---@param label string +function SelectBox:new(parent, label) + SelectBox.super.new(self, parent) + self.type_name = "widget.selectbox" + self.size.x = 200 + (style.padding.x * 2) + self.size.y = self:get_font():get_height() + (style.padding.y * 2) + self.list_container = Widget() + self.list_container.name = self:get_name() + self.list_container:set_size( + self.size.x - self.list_container.border.width, + 150 + ) + self.list = ListBox(self.list_container) + self.list.border.width = 0 + self.list:enable_expand(true) + self.selected = 0 + + local list_on_row_click = self.list.on_row_click + self.list.on_row_click = function(this, idx, data) + list_on_row_click(this, idx, data) + if idx ~= 1 then + self.selected = idx-1 + self:on_selected(idx-1, data) + self:on_change(self.selected) + end + self.list_container:hide_animated(true) + end + + -- Hide list if mouse clicked outside + self.list_container:force_event("mouse_released") + self.list_container.on_mouse_released = function(this, button, x, y) + if + this:is_visible() + and + not this:mouse_on_top(x, y) and not self:mouse_on_top(x, y) + then + this:hide() + return false + end + if this:is_visible() and this:mouse_on_top(x, y) then + return Widget.on_mouse_released(this, button, x, y) + end + end + + self:set_label(label or "select") +end + +---Set the text displayed when no item is selected. +---@param text string +function SelectBox:set_label(text) + SelectBox.super.set_label(self, "- "..text.." -") + if not self.list.rows[1] then + self.list:add_row({"- "..text.." -"}) + else + self.list.rows[1][1] = "- "..text.." -" + end +end + +---Add selectable option to the selectbox. +---@param text widget.styledtext|string +---@param data any +function SelectBox:add_option(text, data) + if type(text) == "string" then + self.list:add_row({ text }, data) + else + self.list:add_row(text, data) + end +end + +---Check if a text is longer than the given maximum width and if larger returns +---a chopped version with the overflow_chars appended to it. +---@param text string +---@param max_width number +---@param font widget.font Default is style.font +---@param overflow_chars? string Default is '...' +---@return string chopped_text +---@return boolean overflows True if the text overflows +function SelectBox:text_overflow(text, max_width, font, overflow_chars) + font = self:get_font(font) + overflow_chars = overflow_chars or "..." + + local overflow = false + local overflow_chars_width = font:get_width(overflow_chars) + + if font:get_width(text) > max_width then + overflow = true + for i = 1, #text do + local reduced_text = text:sub(1, #text - i) + if + font:get_width(reduced_text) + overflow_chars_width + <= + max_width + then + text = reduced_text .. "…" + break + end + end + end + + return text, overflow +end + +---Set the active option index. +---@param idx integer +function SelectBox:set_selected(idx) + if self.list.rows[idx+1] then + self.selected = idx + self.list:set_selected(idx+1) + else + self.selected = 0 + self.list:set_selected() + end + self:on_change(self.selected) +end + +---Get the currently selected option index. +---@return integer +function SelectBox:get_selected() + return self.selected +end + +---Get the currently selected option text. +---@return string|nil +function SelectBox:get_selected_text() + if self.selected > 0 then + return self.list:get_row_text(self.selected + 1) + end + return nil +end + +---Get the currently selected option associated data. +---@return any|nil +function SelectBox:get_selected_data() + if self.selected > 0 then + return self.list:get_row_data(self.selected + 1) + end + return nil +end + +---Repositions the listbox container according to the selectbox position +---and available screensize. +function SelectBox:reposition_container() + local y1 = self.position.y + self:get_height() + local y2 = self.position.y - self.list:get_height() + + local _, h = system.get_window_size(core.window) + + if y1 + self.list:get_height() <= h then + self.list_container:set_position( + self.position.x, + y1 + ) + else + self.list_container:set_position( + self.position.x, + y2 + ) + end + + self.list_container.size.x = self.size.x - (self.border.width * 2) +end + +---Overrided to destroy the floating listbox container. +function SelectBox:destroy_childs() + SelectBox.super.destroy_childs(self) + self.list_container:destroy() +end + +-- +-- Events +-- + +---Overwrite to listen to on_selected events. +---@param item_idx integer +---@param item_data widget.listbox.row +---@diagnostic disable-next-line +function SelectBox:on_selected(item_idx, item_data) end + +function SelectBox:on_mouse_enter(...) + SelectBox.super.on_mouse_enter(self, ...) + self.hover_text = style.accent +end + +function SelectBox:on_mouse_leave(...) + SelectBox.super.on_mouse_leave(self, ...) + self.hover_text = nil +end + +function SelectBox:on_click(button, x, y) + SelectBox.super.on_click(self, button, x, y) + + if button == "left" then + self:reposition_container() + + self.list_container.border.color = style.caret + + self.list_container:toggle_visible(true, true) + + self.list:resize_to_parent() + end +end + +function SelectBox:update() + if not SelectBox.super.update(self) then return false end + + local font = self:get_font() + + self.size.y = font:get_height() + style.padding.y * 2 + + if + self.list_container.visible + and + self.list_container.position.y ~= self.position.y + self:get_height() + then + self:reposition_container() + end + + return true +end + +function SelectBox:draw() + if not SelectBox.super.draw(self) then return false end + + local font = self:get_font() + + local icon_width = style.icon_font:get_width("+") + + local max_width = self.size.x + - icon_width + - (style.padding.x * 2) -- left/right paddings + - (style.padding.x / 2) -- space between icon and text + + local item_text = self.selected == 0 and + self.label or self.list:get_row_text(self.selected+1) + + local text = self:text_overflow(item_text, max_width, font) + + -- draw label or selected item + common.draw_text( + font, + self.hover_text or self.foreground_color or style.text, + text, + "left", + self.position.x + style.padding.x, + self.position.y, + self.size.x - style.padding.x, + self.size.y + ) + + -- draw arrow down icon + common.draw_text( + style.icon_font, + self.hover_text or self.foreground_color or style.text, + "-", + "right", + self.position.x, + self.position.y, + self.size.x - style.padding.x, + self.size.y + ) + + return true +end + + +return SelectBox diff --git a/debian/extra/libraries/widget/textbox.lua b/debian/extra/libraries/widget/textbox.lua new file mode 100644 index 0000000..08abddd --- /dev/null +++ b/debian/extra/libraries/widget/textbox.lua @@ -0,0 +1,308 @@ +-- +-- TextBox widget re-using code from lite's DocView. +-- + +local core = require "core" +local style = require "core.style" +local translate = require "core.doc.translate" +local Doc = require "core.doc" +local DocView = require "core.docview" +local View = require "core.view" +local Widget = require "libraries.widget" + + +---@class widget.textbox.SingleLineDoc : core.doc +---@overload fun():widget.textbox.SingleLineDoc +---@field super core.doc +local SingleLineDoc = Doc:extend() + +function SingleLineDoc:insert(line, col, text) + SingleLineDoc.super.insert(self, line, col, text:gsub("\n", "")) +end + +---@class widget.textbox.TextView : core.docview +---@overload fun():widget.textbox.TextView +---@field super core.docview +local TextView = DocView:extend() + +function TextView:new() + TextView.super.new(self, SingleLineDoc()) + self.gutter_width = 0 + self.hide_lines_gutter = true + self.gutter_text_brightness = 0 + self.scrollable = true + self.font = "font" + self.name = View.get_name(self) + + self.size.y = 0 + self.label = "" +end + +function TextView:get_name() + return self.name +end + +function TextView:get_scrollable_size() + return 0 +end + +function TextView:get_text() + return self.doc:get_text(1, 1, 1, math.huge) +end + +function TextView:set_text(text, select) + self.doc:remove(1, 1, math.huge, math.huge) + self.doc:text_input(text) + if select then + self.doc:set_selection(math.huge, math.huge, 1, 1) + end +end + +function TextView:get_gutter_width() + return self.gutter_width or 0 +end + +function TextView:get_line_height() + return math.floor(self:get_font():get_height() * 1.2) +end + +function TextView:draw_line_gutter(idx, x, y) + if self.hide_lines_gutter then + return + end + TextView.super.draw_line_gutter(self, idx, x, y) +end + +function TextView:draw_line_highlight() + -- no-op function to disable this functionality +end + +-- Overwrite this function just to disable the core.push_clip_rect +function TextView:draw() + self:draw_background(style.background) + local _, indent_size = self.doc:get_indent_info() + self:get_font():set_tab_size(indent_size) + + local minline, maxline = self:get_visible_line_range() + local lh = self:get_line_height() + + local x, y = self:get_line_screen_position(minline) + for i = minline, maxline do + self:draw_line_gutter(i, self.position.x, y) + y = y + lh + end + + x, y = self:get_line_screen_position(minline) + for i = minline, maxline do + self:draw_line_body(i, x, y) + y = y + lh + end + self:draw_overlay() + + self:draw_scrollbar() +end + +---@class widget.textbox : widget +---@overload fun(parent?:widget, text?:string, placeholder?:string):widget.textbox +---@field textview widget.textbox.TextView +---@field placeholder string +---@field placeholder_active boolean +local TextBox = Widget:extend() + +function TextBox:new(parent, text, placeholder) + TextBox.super.new(self, parent) + self.type_name = "widget.textbox" + self.textview = TextView() + self.textview.name = parent.name + self.size.x = 200 + (style.padding.x * 2) + self.textview.size.x = self.size.x + self.size.y = self:get_font():get_height() + (style.padding.y * 2) + self.placeholder = placeholder or "" + self.placeholder_active = false + -- this widget is for text input + self.input_text = true + self.cursor = "ibeam" + self.active = false + self.drag_select = false + + if text ~= "" then + self.textview:set_text(text, select) + else + self.placeholder_active = true + self.textview:set_text(self.placeholder) + end + + local this = self + + function self.textview.doc:on_text_change() + if not this.placeholder_active then + this:on_change(this:get_text()) + end + end + + -- more granular listening of text changing events + local doc_raw_insert = self.textview.doc.raw_insert + function self.textview.doc:raw_insert(...) + doc_raw_insert(self, ...) + this:on_text_change("insert", ...) + end + + local doc_raw_remove = self.textview.doc.raw_remove + function self.textview.doc:raw_remove(...) + doc_raw_remove(self, ...) + this:on_text_change("remove", ...) + end +end + +---@param width integer +function TextBox:set_size(width) + TextBox.super.set_size( + self, + width, + self:get_font():get_height() + (style.padding.y * 2) + ) + self.textview.size.x = self.size.x +end + +--- Get the text displayed on the textbox. +---@return string +function TextBox:get_text() + if self.placeholder_active then + return "" + end + return self.textview:get_text() +end + +--- Set the text displayed on the textbox. +---@param text string +---@param select? boolean +function TextBox:set_text(text, select) + self.textview:set_text(text, select) +end + +-- +-- Events +-- + +function TextBox:on_mouse_pressed(button, x, y, clicks) + if TextBox.super.on_mouse_pressed(self, button, x, y, clicks) then + self.textview:on_mouse_pressed(button, x, y, clicks) + local line, col = self.textview:resolve_screen_position(x, y) + self.drag_select = { line = line, col = col } + self.textview.doc:set_selection(line, col, line, col) + if clicks == 2 then + local line1, col1 = translate.start_of_word(self.textview.doc, line, col) + local line2, col2 = translate.end_of_word(self.textview.doc, line1, col1) + self.textview.doc:set_selection(line2, col2, line1, col1) + elseif clicks == 3 then + self.textview.doc:set_selection(1, 1, 1, math.huge) + end + if core.active_view ~= self.textview then + self.textview:on_mouse_released(button, x, y) + end + return true + end + return false +end + +function TextBox:on_mouse_released(button, x, y) + if TextBox.super.on_mouse_released(self, button, x, y) then + self.drag_select = false + self.textview:on_mouse_released(button, x, y) + return true + end + return false +end + +function TextBox:on_mouse_moved(x, y, dx, dy) + if self.drag_select then + local line, col = self.textview:resolve_screen_position(x, y) + self.textview.doc:set_selection( + self.drag_select.line, self.drag_select.col, line, col + ) + end + if TextBox.super.on_mouse_moved(self, x, y, dx, dy) then + if self.active or core.active_view == self.textview then + self.textview:on_mouse_moved(x, y, dx, dy) + end + return true + end + return false +end + +function TextBox:activate() + self.hover_border = style.caret + if self.placeholder_active then + self.placeholder_active = false + self:set_text("") + end + self.active = true + core.request_cursor("ibeam") +end + +function TextBox:deactivate() + self.hover_border = nil + self.drag_select = false + if self:get_text() == "" then + self.placeholder_active = true + self:set_text(self.placeholder) + end + self.active = false + core.request_cursor("arrow") +end + +function TextBox:on_text_input(text) + TextBox.super.on_text_input(self, text) + self.textview:on_text_input(text) +end + +---Event fired on any text change event. +---@param action string Can be "insert" or "remove", +---insert arguments (see Doc:raw_insert): +--- line, col, text, undo_stack, time +---remove arguments (see Doc:raw_remove): +--- line1, col1, line2, col2, undo_stack, time +---@diagnostic disable-next-line +function TextBox:on_text_change(action, ...) end + +function TextBox:update() + if not TextBox.super.update(self) then return false end + + if + self.drag_select + or + (self.active and self:mouse_on_top(self.mouse.x, self.mouse.y)) + then + core.request_cursor("ibeam") + end + + self.textview:update() + self.size.y = self:get_font():get_height() + (style.padding.y * 2) + + return true +end + +function TextBox:draw() + if not self:is_visible() then return false end + + self.border.color = self.hover_border or style.text + TextBox.super.draw(self) + self.textview.position.x = self.position.x + (style.padding.x / 2) + self.textview.position.y = self.position.y - (style.padding.y/2.5) + self.textview.size.x = self.size.x + self.textview.size.y = self.size.y - (style.padding.y * 2) + + core.push_clip_rect( + self.position.x, + self.position.y, + self.size.x, + self.size.y + ) + self.textview:draw() + core.pop_clip_rect() + + return true +end + + +return TextBox diff --git a/debian/extra/libraries/widget/toggle.lua b/debian/extra/libraries/widget/toggle.lua new file mode 100644 index 0000000..f3ed952 --- /dev/null +++ b/debian/extra/libraries/widget/toggle.lua @@ -0,0 +1,140 @@ +-- +-- Toggle Widget. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local style = require "core.style" +local Widget = require "libraries.widget" +local Label = require "libraries.widget.label" + +-- Hold dimensions of rendered toggle +local BOX = 40 +local TOGGLE = 15 +local BORDER = 3 + +---@class widget.toggle : widget +---@overload fun(parent?:widget, label?:string, enable?:boolean):widget.toggle +---@field public enabled boolean +---@field private caption_label widget.textbox +---@field private padding integer +---@field private switch_x number +---@field private toggle_bg renderer.color +local Toggle = Widget:extend() + +---Constructor +---@param parent widget +---@param label string +---@param enable boolean +function Toggle:new(parent, label, enable) + Toggle.super.new(self, parent) + + self.type_name = "widget.toggle" + + self.enabled = enable or false + self.label = label or "" + + self.caption_label = Label(self, self.label) + self.caption_label:set_position(0, 0) + + self.padding = 2 + self.border.width = 0 + + self:set_size( + self.caption_label:get_width() + (style.padding.x / 2) + (BOX * SCALE), + self.caption_label:get_height() + ((self.padding * 2) * SCALE) + ) + + self.animate_switch = false + self.toggle_x = 0 +end + +---@param enabled boolean +function Toggle:set_toggle(enabled) + self.enabled = enabled + self.animate_switch = true + self:on_change(self.enabled) +end + +---@return boolean +function Toggle:is_toggled() + return self.enabled +end + +function Toggle:toggle() + self.enabled = not self.enabled + self.animate_switch = true + self:on_change(self.enabled) +end + +---@param text string|widget.styledtext +function Toggle:set_label(text) + Toggle.super.set_label(self, text) + self.caption_label:set_label(text) +end + +function Toggle:on_click() + self:toggle() +end + +function Toggle:update() + if not Toggle.super.update(self) then return false end + + local px = style.padding.x / 2 + + self:set_size( + self.caption_label:get_width() + px + (BOX * SCALE), + self.caption_label:get_height() + ((self.padding * 2) * SCALE) + ) + + self.toggle_x = self.caption_label:get_right() + px + + local switch_x = self.enabled and + self.position.x + self.toggle_x + + ((BOX - TOGGLE - BORDER) * SCALE) + or + self.position.x + self.toggle_x + (BORDER * SCALE) + + if not self.animate_switch then + self.switch_x = switch_x + self.toggle_bg = {} + local color = self.enabled and style.caret or style.line_number + for i=1, 4, 1 do self.toggle_bg[i] = color[i] end + else + local color = self.enabled and style.caret or style.line_number + self:move_towards(self, "switch_x", switch_x, 0.2) + for i=1, 4, 1 do + self:move_towards(self.toggle_bg, i, color[i], 0.2) + end + if self.switch_x == switch_x then + self.animate_switch = false + end + end + + return true +end + +function Toggle:draw() + if not Toggle.super.draw(self) then return false end + + renderer.draw_rect( + self.position.x + self.toggle_x, + self.position.y, + BOX * SCALE, + self.size.y, + self.toggle_bg + ) + + renderer.draw_rect( + self.switch_x, + self.position.y + (BORDER * SCALE), + TOGGLE * SCALE, + self.size.y - ((BORDER * 2) * SCALE), + style.line_highlight + ) + + return true +end + + +return Toggle diff --git a/debian/extra/libraries/widget/treelist.lua b/debian/extra/libraries/widget/treelist.lua new file mode 100644 index 0000000..758db49 --- /dev/null +++ b/debian/extra/libraries/widget/treelist.lua @@ -0,0 +1,609 @@ +-- +-- TreeList Widget heavily based on TreeView plugin. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local core = require "core" +local common = require "core.common" +local style = require "core.style" +local Widget = require "libraries.widget" + +---@class widget.treelist.item +---@field name string +---@field label string +---@field data any? +---@field expanded boolean? +---@field visible boolean? +---@field tooltip string? +---@field depth integer? +---@field childs widget.treelist.item[]? +---@field parent widget.treelist.item[]? +---@field icon string? + +---@class widget.treelist : widget +---@field items widget.treelist.item[] +---@field selected_item widget.treelist.item? +---@field hovered_item widget.treelist.item? +---@field icon_font renderer.font? +---@field private count_lines integer +---@field private scroll_width integer +---@overload fun(parent:widget?):widget.treelist +local TreeList = Widget:extend() + +---Constructor +---@param parent? widget +function TreeList:new(parent) + TreeList.super.new(self, parent) + + self.type_name = "widget.treelist" + + self.scrollable = true + self.init_size = true + self.count_lines = 0 + self.scroll_width = 0 + self.items = {} + self.tooltip = { x = 0, y = 0, begin = 0, alpha = 0 } + self.last_scroll_y = 0 + + self.item_icon_width = 0 + self.item_text_spacing = 0 +end + +---Get the height of a single item. +---@return number h +function TreeList:get_item_height() + return style.font:get_height() + style.padding.y +end + +---Add new item to to tree list +---@param item widget.treelist.item +function TreeList:add_item(item) + table.insert(self.items, item) +end + +---Remove all items from the tree +function TreeList:clear() + self.items = {} + self.selected_item = nil + self.hovered_item = nil +end + +---Retrieve the amount of visible items and also yield them. +---@param item widget.treelist.item +---@param x number +---@param y number +---@param w number +---@param h number +---@param depth? number +---@return integer items_count +function TreeList:get_items(item, x, y, w, h, depth) + if not depth then depth = 0 else depth = depth + 1 end + item.depth = depth + coroutine.yield(item, x, y, w, h) + local count_lines = 1 + if item and item.childs and item.expanded then + for _, child in ipairs(item.childs) do + if child.visible ~= false then + count_lines = count_lines + self:get_items( + child, x, y + count_lines * h, w, h, depth + ) + end + end + end + return count_lines +end + +---Allows iterating the currently visible items only. +---@return fun():widget.treelist.item,number,number,number,number +function TreeList:each_item() + return coroutine.wrap(function() + local count_lines = 0 + local ox, oy = self:get_content_offset() + local h = self:get_item_height() + if #self.items > 0 then + for i=1, #self.items do + count_lines = count_lines + self:get_items( + self.items[i], + ox, oy + style.padding.y + h * count_lines, + self.size.x, h + ) + end + end + self.count_lines = count_lines + end) +end + +---Retrieve an item by name using the query format: +---"parent_name>child_name_2>child_name_2>etc..." +---@param query string +---@param items? widget.treelist.item[] +---@param separator? string Use a different separator (default: >) +---@return widget.treelist.item? +function TreeList:query_item(query, items, separator) + local parent = items or self.items + local item = nil + separator = separator or ">" + for name in query:gmatch("([^"..separator.."]+)") do + if parent then + local found = false + for _, child in ipairs(parent) do + if name == child.name then + item = child + parent = child.childs + found = true + break + end + end + if not found then return nil end + else + return nil + end + end + return item +end + +---Set the active item. +---@param selection widget.treelist.item +---@param selection_y? number +---@param center? boolean +---@param instant? boolean +function TreeList:set_selection(selection, selection_y, center, instant) + self.selected_item = selection + if selection and selection_y + and (selection_y <= 0 or selection_y >= self.size.y) then + local lh = self:get_item_height() + if not center and selection_y >= self.size.y - lh then + selection_y = selection_y - self.size.y + lh + end + if center then + selection_y = selection_y - (self.size.y - lh) / 2 + end + local _, y = self:get_content_offset() + self.scroll.to.y = selection_y - y + self.scroll.to.y = common.clamp( + self.scroll.to.y, 0, self:get_scrollable_size() - self.size.y + ) + if instant then + self.scroll.y = self.scroll.to.y + end + end +end + +---Sets the selection to the file with the specified path. +---TODO: Not tested, idea is to allow query like selections using item names +---by introducing a get_item/set_item methods that accepts a string query, +---For the moment we leave this inherited TreeView function here. +---@param path string #Absolute path of item to select +---@param expand boolean #Expand dirs leading to the item +---@param scroll_to boolean #Scroll to make the item visible +---@param instant boolean #Don't animate the scroll +---@return table? #The selected item +function TreeList:set_selection_from_path(path, expand, scroll_to, instant) + local separator = "||" + local to_select, to_select_y + local let_it_finish, done + ::restart:: + for item, _,y,_,_ in self:each_item() do + if not done then + if item.childs and #item.childs > 0 then + local _, to = string.find(path, item.name..separator, 1, true) + if to and to == #item.name + #separator then + to_select, to_select_y = item, y + if expand and not item.expanded then + self:toggle_expand(true, item) + -- Because we altered the size of the TreeList + -- and because TreeList:get_scrollable_size uses self.count_lines + -- which gets updated only when TreeList:each_item finishes, + -- we can't stop here or we risk that the scroll + -- gets clamped by View:clamp_scroll_position. + let_it_finish = true + -- We need to restart the process because if TreeList:toggle_expand + -- altered the cache, TreeList:each_item risks looping indefinitely. + goto restart + end + end + else + if item.name == path then + to_select, to_select_y = item, y + done = true + if not let_it_finish then break end + end + end + end + end + if to_select then + self:set_selection(to_select, scroll_to and to_select_y, true, instant) + end + return to_select +end + +---Set the icon font used to render the items icon. +---@param font renderer.font +function TreeList:set_icon_font(font) + if font:get_size() ~= style.icon_font:get_size() then + font:set_size(style.icon_font:get_size()) + end + self.icon_font = font +end + +---Keep the icon font size updated to match current scale. +function TreeList:on_scale_change() + if self.icon_font then + self.icon_font:set_size(style.icon_font:get_size()) + end +end + +function TreeList:on_mouse_moved(px, py, ...) + if TreeList.super.on_mouse_moved(self, px, py, ...) then + self.hovered_item = nil + else + return false + end + + local position = self:get_position() + local item_changed, tooltip_changed + for item, x,y,w,h in self:each_item() do + if px > x and py > y and px <= (self.size.x + position.x) and py <= y + h then + item_changed = true + self.hovered_item = item + + x = math.max(x, self.position.x) + if px > x and py > y and px <= x + w and py <= y + h then + tooltip_changed = true + self.tooltip.x, self.tooltip.y = px, py + self.tooltip.begin = system.get_time() + end + break + end + end + if not item_changed then self.hovered_item = nil end + if not tooltip_changed then self.tooltip.x, self.tooltip.y = nil, nil end + + return true +end + +---Override to listen for item click events. +---@param item widget.treelist.item +---@param button string +---@param clicks integer +function TreeList:on_item_click(item, button, x, y, clicks) end + +function TreeList:on_mouse_pressed(button, x, y, clicks) + if TreeList.super.on_mouse_pressed(self, button, x, y, clicks) then + if self:scrollbar_hovering() then return true end + self:set_selection(self.hovered_item) + if self.hovered_item then + local emit_click = false + if clicks > 1 then + self:toggle_expand() + else + if self.hovered_item.childs then + local x1, x2 = self:get_chevron_position(self.hovered_item) + if x >= x1 and x <= x2 then + self:toggle_expand() + else + emit_click = true + end + else + emit_click = true + end + end + if emit_click then + self:on_item_click(self.hovered_item, button, x, y, clicks) + end + end + return true + end + return false +end + +function TreeList:on_mouse_left() + TreeList.super.on_mouse_left(self) + self.hovered_item = nil +end + +function TreeList:update() + if not self:is_visible() then return end + + local duration = system.get_time() - self.tooltip.begin + local tooltip_delay = 0.5 + if self.hovered_item and self.tooltip.x and duration > tooltip_delay then + self:move_towards(self.tooltip, "alpha", 255, 1, "treeview") + else + self.tooltip.alpha = 0 + end + + self.item_icon_width = style.icon_font:get_width("D") + self.item_text_spacing = style.icon_font:get_width("f") / 2 + + -- this will make sure hovered_item is updated + local dy = math.abs(self.last_scroll_y - self.scroll.y) + if dy > 0 then + self:on_mouse_moved(core.root_view.mouse.x, core.root_view.mouse.y, 0, 0) + self.last_scroll_y = self.scroll.y + end + + TreeList.super.update(self) +end + +function TreeList:get_scrollable_size() + return self.count_lines and self:get_item_height() * (self.count_lines + 1) or math.huge +end + +function TreeList:get_h_scrollable_size() + local _, _, v_scroll_w = self.v_scrollbar:get_thumb_rect() + return self.scroll_width + ( + self.size.x > self.scroll_width + v_scroll_w and 0 or style.padding.x + ) +end + +local function replace_alpha(color, alpha) + local r, g, b = table.unpack(color) + return { r, g, b, alpha } +end + +function TreeList:draw_tooltip() + if not self.hovered_item or not self.hovered_item.tooltip then + return + end + + local text = common.home_encode(self.hovered_item.tooltip) + local w, h = style.font:get_width(text), style.font:get_height() + + local tooltip_offset = style.font:get_height() + local x, y = self.tooltip.x + tooltip_offset, self.tooltip.y + tooltip_offset + w, h = w + style.padding.x, h + style.padding.y + + if x + w > core.root_view.root_node.size.x then -- check if we can span right + x = x - w -- span left instead + end + + local tooltip_border = 1 + local bx, by = x - tooltip_border, y - tooltip_border + local bw, bh = w + 2 * tooltip_border, h + 2 * tooltip_border + renderer.draw_rect( + bx, by, bw, bh, replace_alpha(style.text, self.tooltip.alpha) + ) + renderer.draw_rect( + x, y, w, h, replace_alpha(style.background2, self.tooltip.alpha) + ) + common.draw_text( + style.font, + replace_alpha(style.text, self.tooltip.alpha), + text, "center", x, y, w, h + ) +end + +---@param item widget.treelist.item +---@param active boolean +---@param hovered boolean +function TreeList:get_item_icon(item, active, hovered) + local character = item.icon + local font = self.icon_font or style.icon_font + local color = style.text + if active or hovered then + color = style.accent + end + return character, font, color +end + +---@param item widget.treelist.item +---@param active boolean +---@param hovered boolean +function TreeList:get_item_text(item, active, hovered) + local text = item.label + local font = style.font + local color = style.text + if active or hovered then + color = style.accent + end + return text, font, color +end + +---@param item widget.treelist.item +---@param active boolean +---@param hovered boolean +---@param x number +---@param y number +---@param w number +---@param h number +function TreeList:draw_item_text(item, active, hovered, x, y, w, h) + local item_text, item_font, item_color = self:get_item_text(item, active, hovered) + return common.draw_text(item_font, item_color, item_text, "left", x, y, 0, h) +end + +---@param item widget.treelist.item +---@param active boolean +---@param hovered boolean +---@param x number +---@param y number +---@param w number +---@param h number +function TreeList:draw_item_icon(item, active, hovered, x, y, w, h) + local icon_char, icon_font, icon_color = self:get_item_icon(item, active, hovered) + if not icon_char then return 0 end + common.draw_text(icon_font, icon_color, icon_char, "left", x, y, 0, h) + return self.item_icon_width + self.item_text_spacing +end + +---@param item widget.treelist.item +---@param active boolean +---@param hovered boolean +---@param x number +---@param y number +---@param w number +---@param h number +function TreeList:draw_item_body(item, active, hovered, x, y, w, h) + x = x + self:draw_item_icon(item, active, hovered, x, y, w, h) + return self:draw_item_text(item, active, hovered, x, y, w, h) +end + +---@param item widget.treelist.item +---@param active boolean +---@param hovered boolean +---@param x number +---@param y number +---@param w number +---@param h number +function TreeList:draw_item_chevron(item, active, hovered, x, y, w, h) + if item.childs and #item.childs > 0 then + local chevron_icon = item.expanded and "-" or "+" + local chevron_color = hovered and style.accent or style.text + common.draw_text(style.icon_font, chevron_color, chevron_icon, "left", x, y, 0, h) + end + return style.padding.x +end + +---Get an item chevron starting and ending positions. +---@return number x1 +---@return number x2 +function TreeList:get_chevron_position(item) + local ox = self:get_content_offset() + local x1 = ox + item.depth * style.padding.x + local x2 = x1 + style.padding.x * 2 + return x1, x2 +end + +---@param item widget.treelist.item +---@param active boolean +---@param hovered boolean +---@param x number +---@param y number +---@param w number +---@param h number +function TreeList:draw_item_background(item, active, hovered, x, y, w, h) + if hovered then + local hover_color = { table.unpack(style.line_highlight) } + hover_color[4] = 160 + renderer.draw_rect(self.position.x, y, self.size.x, h, hover_color) + elseif active then + renderer.draw_rect(self.position.x, y, self.size.x, h, style.line_highlight) + end +end + +---@param item widget.treelist.item +---@param active boolean +---@param hovered boolean +---@param x number +---@param y number +---@param w number +---@param h number +function TreeList:draw_item(item, active, hovered, x, y, w, h) + self:draw_item_background(item, active, hovered, x, y, w, h) + + x = x + item.depth * style.padding.x + style.padding.x + x = x + self:draw_item_chevron(item, active, hovered, x, y, w, h) + + return self:draw_item_body(item, active, hovered, x, y, w, h) +end + +function TreeList:draw() + if not TreeList.super.draw(self) then return end + + local position, ox = self:get_position(), self:get_content_offset() + local _y, _h, sw = position.y, self.size.y, 0 + for item, x,y,w,h in self:each_item() do + if y + h >= _y and y < _y + _h then + w = self:draw_item( + item, + item == self.selected_item, + item == self.hovered_item, + x, y, w, h + ) - position.x + (position.x - ox) + sw = math.max(w, sw) + end + end + self.scroll_width = sw + + self:draw_scrollbar() + + if + self.hovered_item and self.hovered_item.tooltip + and + self.tooltip.x and self.tooltip.alpha > 0 + then + core.root_view:defer_draw(self.draw_tooltip, self) + end +end + +---@param item? widget.treelist.item +---@param where integer +---@return widget.treelist.item item +---@return number x +---@return number y +---@return number w +---@return number h +function TreeList:get_item(item, where) + item = item or self.selected_item + + local last_item, last_x, last_y, last_w, last_h + local stop = false + + for it, x, y, w, h in self:each_item() do + if not item and where >= 0 then + return it, x, y, w, h + end + if item == it then + if where < 0 and last_item then + break + elseif where == 0 or (where < 0 and not last_item) then + return it, x, y, w, h + end + stop = true + elseif stop then + item = it + return it, x, y, w, h + end + last_item, last_x, last_y, last_w, last_h = it, x, y, w, h + end + return last_item, last_x, last_y, last_w, last_h +end + +---@param item? widget.treelist.item +---@return widget.treelist.item item +---@return number x +---@return number y +---@return number w +---@return number h +function TreeList:get_next(item) + return self:get_item(item, 1) +end + +---@param item? widget.treelist.item +---@return widget.treelist.item item +---@return number x +---@return number y +---@return number w +---@return number h +function TreeList:get_previous(item) + return self:get_item(item, -1) +end + +function TreeList:select_next() + self.selected_item = self:get_next() +end + +function TreeList:select_prev() + self.selected_item = self:get_previous() +end + +---Expand or collapse the currently selected or given item. +---@param toggle? boolean +---@param item? widget.treelist.item +function TreeList:toggle_expand(toggle, item) + item = item or self.selected_item + + if not item then return end + + if item.childs and #item.childs > 0 then + if type(toggle) == "boolean" then + item.expanded = toggle + else + item.expanded = not item.expanded + end + end +end + + +return TreeList diff --git a/debian/extra/plugins/fontconfig.lua b/debian/extra/plugins/fontconfig.lua new file mode 100644 index 0000000..03a2f95 --- /dev/null +++ b/debian/extra/plugins/fontconfig.lua @@ -0,0 +1,118 @@ +-- mod-version:3 +local subprocess = require "process" + +local core = require "core" +local style = require "core.style" +local config = require "core.config" +local common = require "core.common" + +config.plugins.fontconfig = common.merge({ prefix = "" }, config.plugins.fontconfig) + +--[[ + Example config (put it in user module): + + ``` + local fontconfig = require "plugins.fontconfig" + fontconfig.use { + font = { name = 'sans', size = 13 * SCALE }, + code_font = { name = 'monospace', size = 13 * SCALE }, + } + ``` + + if you want the fonts to load instantaneously on startup, + you can try your luck on fontconfig.use_blocking. I won't be responsible for + the slow startup time. +]] + +local function resolve_font(spec) + local scan_rate = 1 / config.fps + local proc = subprocess.start({ config.plugins.fontconfig.prefix .. "fc-match", "-s", "-f", "%{file}\n", spec }, { + stdin = subprocess.REDIRECT_DISCARD, + stdout = subprocess.REDIRECT_PIPE, + stderr = subprocess.REDIRECT_STDOUT + }) + local prev + local lines = {} + while true do + coroutine.yield(scan_rate) + local buf = proc:read_stdout() + if not buf then break end + + local last_line_start = 1 + for line, ln in string.gmatch(buf, "([^\n]-)\n()") do + last_line_start = ln + if prev then line = prev .. line end + table.insert(lines, line) + end + prev = last_line_start < #buf and string.sub(buf, last_line_start) + end + if prev then table.insert(lines, prev) end + + if proc:returncode() ~= 0 or #lines < 1 then + error(string.format("Cannot find a font matching the given specs: %q", spec), 0) + end + return lines[1] +end + + +local M = {} + +function M.load(font_name, font_size, font_opt) + local font_file = resolve_font(font_name) + return renderer.font.load(font_file, font_size, font_opt) +end + +function M.load_blocking(font_name, font_size, font_opt) + local co = coroutine.create(function() + return M.load(font_name, font_size, font_opt) + end) + local result + while coroutine.status(co) ~= "dead" do + local ok, err = coroutine.resume(co) + if not ok then error(err) end + result = err + end + return result +end + +function M.load_group_blocking(group, font_size, font_opt) + local fonts = {} + for i in ipairs(group) do + local co = coroutine.create(function() + return M.load(group[i], font_size, font_opt) + end) + local result + while coroutine.status(co) ~= "dead" do + local ok, err = coroutine.resume(co) + if not ok then error(err) end + result = err + end + table.insert(fonts, result) + end + + return renderer.font.group(fonts) +end + +function M.use(spec) + core.add_thread(function() + for key, value in pairs(spec) do + style[key] = M.load(value.name, value.size, value) + end + end) +end + +-- there is basically no need for this, but for the sake of completeness +-- I'll leave this here +function M.use_blocking(spec) + for key, value in pairs(spec) do + local font + if value.group then + font = M.load_group_blocking(value.group, value.size, value) + else + font = M.load_blocking(value.name, value.size, value) + end + style[key] = font + end +end + +return M diff --git a/debian/extra/plugins/gitopen.lua b/debian/extra/plugins/gitopen.lua new file mode 100644 index 0000000..4c5a2ac --- /dev/null +++ b/debian/extra/plugins/gitopen.lua @@ -0,0 +1,51 @@ +-- mod-version:3 +local core = require "core" +local command = require "core.command" +local common = require "core.common" +local config = require "core.config" + +local function exec(cmd) + local proc = process.start(cmd) + while proc:running() do + coroutine.yield(0.1) + end + if proc:returncode() > 0 then + core.error("ERROR - command: " .. table.concat(cmd, " ")) + end + return proc:read_stdout() or "" +end + +local function git_find_files_and_open(commit) + local git_root = exec({"git", "rev-parse", "--show-toplevel"}):match("^%s*(.-)%s*$") + local file_list_str = exec({"git", "show", "--name-only", "--pretty=format:", commit}) + + for str in string.gmatch(file_list_str, "([^\n]+)") do + -- Nomalize path as Git for Windows uses / as Unix based systems + local filename = common.normalize_path(git_root .. PATHSEP .. str) + + -- Only open files within the commit whose names do not match the configured ignore file patterns + if not common.match_pattern(common.basename(filename), config.ignore_files) then + core.root_view:open_doc(core.open_doc(filename)) + end + end +end + +-- works in any context +command.add(nil, { + ["gitopen:open-from-commit"] = function(dv) + core.command_view:enter("Which commit? (default=HEAD)", { + submit = function(commit) + if commit == nil or commit == "" then + commit = "HEAD" + end + -- open the files in the background, return immediately + core.add_thread( + function () + git_find_files_and_open(commit) + end + ) + end + }) + end, +}) + diff --git a/debian/extra/plugins/gitstatus.lua b/debian/extra/plugins/gitstatus.lua new file mode 100644 index 0000000..04f6b15 --- /dev/null +++ b/debian/extra/plugins/gitstatus.lua @@ -0,0 +1,155 @@ +-- mod-version:3 +local core = require "core" +local common = require "core.common" +local config = require "core.config" +local style = require "core.style" +local StatusView = require "core.statusview" +local TreeView = require "plugins.treeview" + +config.plugins.gitstatus = common.merge({ + color_icons = true, + recurse_submodules = true, + -- The config specification used by the settings gui + config_spec = { + name = "Git Status", + { + label = "Colorize icons", + description = "Colorize the icons as well", + path = "color_icons", + type = "toggle", + default = true + }, + { + label = "Recurse Submodules", + description = "Also retrieve git stats from submodules.", + path = "recurse_submodules", + type = "toggle", + default = true + } + } +}, config.plugins.gitstatus) + +style.gitstatus_addition = {common.color "#587c0c"} +style.gitstatus_modification = {common.color "#0c7d9d"} +style.gitstatus_deletion = {common.color "#94151b"} + +local scan_rate = config.project_scan_rate or 5 +local cached_color_for_item = {} + + +-- Override TreeView's get_item_text to add modification color +local treeview_get_item_text = TreeView.get_item_text +function TreeView:get_item_text(item, active, hovered) + local text, font, color = treeview_get_item_text(self, item, active, hovered) + if cached_color_for_item[item.abs_filename] then + color = cached_color_for_item[item.abs_filename] + end + return text, font, color +end + +-- Override TreeView's get_item_icon to add modification color +local treeview_get_item_icon = TreeView.get_item_icon +function TreeView:get_item_icon(item, active, hovered) + local character, font, color = treeview_get_item_icon(self, item, active, hovered) + if config.plugins.gitstatus and config.plugins.gitstatus.color_icons and cached_color_for_item[item.abs_filename] then + color = cached_color_for_item[item.abs_filename] + end + return character, font, color +end + +local git = { + branch = nil, + inserts = 0, + deletes = 0, +} + +local function exec(cmd) + local proc = process.start(cmd) + -- Don't use proc:wait() here - that will freeze the app. + -- Instead, rely on the fact that this is only called within + -- a coroutine, and yield for a fraction of a second, allowing + -- other stuff to happen while we wait for the process to complete. + while proc:running() do + coroutine.yield(0.1) + end + return proc:read_stdout() or "" +end + + +core.add_thread(function() + while true do + if system.get_file_info(".git") then + -- get branch name + git.branch = exec({"git", "rev-parse", "--abbrev-ref", "HEAD"}):match("[^\n]*") + + local inserts = 0 + local deletes = 0 + + -- get diff + local diff = exec({"git", "diff", "--numstat"}) + if + config.plugins.gitstatus.recurse_submodules + and + system.get_file_info(".gitmodules") + then + local diff2 = exec({"git", "submodule", "foreach", "git diff --numstat"}) + diff = diff .. diff2 + end + + -- forget the old state + cached_color_for_item = {} + + local folder = core.project_dir + for line in string.gmatch(diff, "[^\n]+") do + local submodule = line:match("^Entering '(.+)'$") + if submodule then + folder = core.project_dir .. PATHSEP .. submodule + else + local ins, dels, path = line:match("(%d+)%s+(%d+)%s+(.+)") + if path then + inserts = inserts + (tonumber(ins) or 0) + deletes = deletes + (tonumber(dels) or 0) + local abs_path = folder .. PATHSEP .. path + -- Color this file, and each parent folder, + -- so you can see at a glance which folders + -- have modified files in them. + while abs_path do + cached_color_for_item[abs_path] = style.gitstatus_modification + abs_path = common.dirname(abs_path) + end + end + end + end + + git.inserts = inserts + git.deletes = deletes + + else + git.branch = nil + end + + coroutine.yield(scan_rate) + end +end) + + +core.status_view:add_item({ + name = "status:git", + alignment = StatusView.Item.RIGHT, + get_item = function() + if not git.branch then + return {} + end + return { + (git.inserts ~= 0 or git.deletes ~= 0) and style.accent or style.text, + git.branch, + style.dim, " ", + git.inserts ~= 0 and style.accent or style.text, "+", git.inserts, + style.dim, " / ", + git.deletes ~= 0 and style.accent or style.text, "-", git.deletes, + } + end, + position = -1, + tooltip = "branch and changes", + separator = core.status_view.separator2 +}) diff --git a/debian/extra/plugins/language_R.lua b/debian/extra/plugins/language_R.lua new file mode 100644 index 0000000..afe3d1e --- /dev/null +++ b/debian/extra/plugins/language_R.lua @@ -0,0 +1,39 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add{ + name = "R", + files = {"%.r$", "%.rds$", "%.rda$", "%.rdata$", "%.R$"}, + comment = "#", + patterns = { + {pattern = {"#", "\n"}, type = "comment"}, + {pattern = {'"', '"'}, type = "string"}, + {pattern = {"'", "'"}, type = "string"}, + {pattern = "[%a_][%w_]*%f[(]", type = "function"}, + {pattern = "[%a_][%w_]*", type = "symbol"}, + {pattern = "[%+%-=/%*%^%%<>!|&]", type = "operator"}, + {pattern = "0x[%da-fA-F]+", type = "number"}, + {pattern = "-?%d+[%d%.eE]*", type = "number"}, + {pattern = "-?%.?%d+", type = "number"}, + }, + symbols = { + ["TRUE"] = "literal", + ["FALSE"] = "literal", + ["NA"] = "literal", + ["NULL"] = "literal", + ["Inf"] = "literal", + ["if"] = "keyword", + ["else"] = "keyword", + ["while"] = "keyword", + ["function"] = "keyword", + ["break"] = "keyword", + ["next"] = "keyword", + ["repeat"] = "keyword", + ["in"] = "keyword", + ["for"] = "keyword", + ["NA_integer"] = "keyword", + ["NA_complex"] = "keyword", + ["NA_character"] = "keyword", + ["NA_real"] = "keyword" + } +} diff --git a/debian/extra/plugins/language_angelscript.lua b/debian/extra/plugins/language_angelscript.lua new file mode 100644 index 0000000..4e003ea --- /dev/null +++ b/debian/extra/plugins/language_angelscript.lua @@ -0,0 +1,88 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "AngelScript", + files = { "%.as$", "%.asc$" }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { "#", "[^\\]\n" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?0[xX]%x+", type = "number" }, + { pattern = "-?0[bB][0-1]+", type = "number" }, + { pattern = "-?0[oO][0-7]+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "&inout", type = "keyword" }, + { pattern = "&in", type = "keyword" }, + { pattern = "&out", type = "keyword" }, + { pattern = "[%a_][%w_]*@", type = "keyword2" }, + { pattern = "[%-%+!~@%?:&|%^<>%*/=%%]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + -- Common + ["shared"] = "keyword", + ["external"] = "keyword", + ["private"] = "keyword", + ["protected"] = "keyword", + ["const"] = "keyword", + ["final"] = "keyword", + ["abstract"] = "keyword", + ["class"] = "keyword", + ["typedef"] = "keyword", + ["namespace"] = "keyword", + ["interface"] = "keyword", + ["import"] = "keyword", + ["enum"] = "keyword", + ["funcdef"] = "keyword", + ["get"] = "keyword", + ["set"] = "keyword", + ["mixin"] = "keyword", + ["void"] = "keyword2", + ["int"] = "keyword2", + ["int8"] = "keyword2", + ["int16"] = "keyword2", + ["int32"] = "keyword2", + ["int64"] = "keyword2", + ["uint"] = "keyword2", + ["uint8"] = "keyword2", + ["uint16"] = "keyword2", + ["uint32"] = "keyword2", + ["uint64"] = "keyword2", + ["float"] = "keyword2", + ["double"] = "keyword2", + ["bool"] = "keyword2", + ["auto"] = "keyword", + ["override"] = "keyword", + ["explicit"] = "keyword", + ["property"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["return"] = "keyword", + ["switch"] = "keyword", + ["case"] = "keyword", + ["default"] = "keyword", + ["for"] = "keyword", + ["while"] = "keyword", + ["do"] = "keyword", + ["if"] = "keyword", + ["else"] = "keyword", + ["try"] = "keyword", + ["catch"] = "keyword", + ["cast"] = "keyword", + ["function"] = "keyword", + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + ["is"] = "operator", + ["and"] = "operator", + ["or"] = "operator", + ["xor"] = "operator", + }, +} + diff --git a/debian/extra/plugins/language_assembly_riscv.lua b/debian/extra/plugins/language_assembly_riscv.lua new file mode 100644 index 0000000..c3fa254 --- /dev/null +++ b/debian/extra/plugins/language_assembly_riscv.lua @@ -0,0 +1,538 @@ +-- mod-version:3 +-- Support for RISC-V assembly +-- Note: kinda conflicts with x86 asm, must uninstall it or use force-syntax plugin +-- https://github.com/cheyao +local syntax = require "core.syntax" + +syntax.add { + name = "RISC-V Assembly", + files = { "%.asm$", "%.[sS]$" }, + comment = "#", + patterns = { + { pattern = "#.*\n", type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "0[bB][0-1]+%W", type = "number" }, + { pattern = "0[xX]%x+", type = "number" }, + { pattern = "%%+[%a_][%w_]*", type = "function" }, + { pattern = "[%a%._][%w%._]*:%W", type = "function" }, + { pattern = "[^%p%a]%-?%d[%d%.]*", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&%$]", type = "operator" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "%.%a+", type = "normal" } + }, + symbols = { + -- Integer Registers + ["x0"] = "literal", + ["x1"] = "literal", + ["x2"] = "literal", + ["x3"] = "literal", + ["x4"] = "literal", + ["x5"] = "literal", + ["x6"] = "literal", + ["x7"] = "literal", + ["x8"] = "literal", + ["x9"] = "literal", + ["x10"] = "literal", + ["x11"] = "literal", + ["x12"] = "literal", + ["x13"] = "literal", + ["x14"] = "literal", + ["x15"] = "literal", + ["x16"] = "literal", + ["x17"] = "literal", + ["x18"] = "literal", + ["x19"] = "literal", + ["x20"] = "literal", + ["x21"] = "literal", + ["x22"] = "literal", + ["x23"] = "literal", + ["x24"] = "literal", + ["x25"] = "literal", + ["x26"] = "literal", + ["x27"] = "literal", + ["x28"] = "literal", + ["x29"] = "literal", + ["x30"] = "literal", + ["x31"] = "literal", + ["zero"] = "literal", + ["ra"] = "literal", + ["sp"] = "literal", + ["gp"] = "literal", + ["tp"] = "literal", + ["t0"] = "literal", + ["t1"] = "literal", + ["t2"] = "literal", + ["fp"] = "literal", + ["s0"] = "literal", + ["s1"] = "literal", + ["a0"] = "literal", + ["a1"] = "literal", + ["a2"] = "literal", + ["a3"] = "literal", + ["a4"] = "literal", + ["a5"] = "literal", + ["a6"] = "literal", + ["a7"] = "literal", + ["s2"] = "literal", + ["s3"] = "literal", + ["s4"] = "literal", + ["s5"] = "literal", + ["s6"] = "literal", + ["s7"] = "literal", + ["s8"] = "literal", + ["s9"] = "literal", + ["s10"] = "literal", + ["s11"] = "literal", + ["t3"] = "literal", + ["t4"] = "literal", + ["t5"] = "literal", + ["t6"] = "literal", + ["pc"] = "literal", + -- Floating-point Registers + ["f0"] = "literal", + ["f1"] = "literal", + ["f2"] = "literal", + ["f3"] = "literal", + ["f4"] = "literal", + ["f5"] = "literal", + ["f6"] = "literal", + ["f7"] = "literal", + ["f8"] = "literal", + ["f9"] = "literal", + ["f10"] = "literal", + ["f11"] = "literal", + ["f12"] = "literal", + ["f13"] = "literal", + ["f14"] = "literal", + ["f15"] = "literal", + ["f16"] = "literal", + ["f17"] = "literal", + ["f18"] = "literal", + ["f19"] = "literal", + ["f20"] = "literal", + ["f21"] = "literal", + ["f22"] = "literal", + ["f23"] = "literal", + ["f24"] = "literal", + ["f25"] = "literal", + ["f26"] = "literal", + ["f27"] = "literal", + ["f28"] = "literal", + ["f29"] = "literal", + ["f30"] = "literal", + ["f31"] = "literal", + + ["ft0"] = "literal", + ["ft1"] = "literal", + ["ft2"] = "literal", + ["ft3"] = "literal", + ["ft4"] = "literal", + ["ft5"] = "literal", + ["ft6"] = "literal", + ["ft7"] = "literal", + + ["fs0"] = "literal", + ["fs1"] = "literal", + + ["fa0"] = "literal", + ["fa1"] = "literal", + ["fa2"] = "literal", + ["fa3"] = "literal", + ["fa4"] = "literal", + ["fa5"] = "literal", + ["fa6"] = "literal", + ["fa7"] = "literal", + + ["fa2"] = "literal", + ["fa3"] = "literal", + ["fa4"] = "literal", + ["fa5"] = "literal", + ["fa6"] = "literal", + ["fa7"] = "literal", + ["fa8"] = "literal", + ["fa9"] = "literal", + ["fa10"] = "literal", + ["fa11"] = "literal", + + ["ft8"] = "literal", + ["ft9"] = "literal", + ["ft10"] = "literal", + ["ft11"] = "literal", + + -- Vector Registers + ["v0"] = "literal", + ["v1"] = "literal", + ["v2"] = "literal", + ["v3"] = "literal", + ["v4"] = "literal", + ["v5"] = "literal", + ["v6"] = "literal", + ["v7"] = "literal", + ["v8"] = "literal", + ["v9"] = "literal", + ["v10"] = "literal", + ["v11"] = "literal", + ["v12"] = "literal", + ["v13"] = "literal", + ["v14"] = "literal", + ["v15"] = "literal", + ["v16"] = "literal", + ["v17"] = "literal", + ["v18"] = "literal", + ["v19"] = "literal", + ["v20"] = "literal", + ["v21"] = "literal", + ["v22"] = "literal", + ["v23"] = "literal", + ["v24"] = "literal", + ["v25"] = "literal", + ["v26"] = "literal", + ["v27"] = "literal", + ["v28"] = "literal", + ["v29"] = "literal", + ["v30"] = "literal", + ["v31"] = "literal", + + ["vl"] = "literal", + ["vtype"] = "literal", + ["vzrm"] = "literal", + ["vxsat"] = "literal", + + -- RV32I instructions + ["lui"] = "keyword", + ["auipc"] = "keyword", + ["jal"] = "keyword", + ["jalr"] = "keyword", + ["beq"] = "keyword", + ["bne"] = "keyword", + ["blt"] = "keyword", + ["bge"] = "keyword", + ["bltu"] = "keyword", + ["bgeu"] = "keyword", + ["lb"] = "keyword", + ["lh"] = "keyword", + ["lw"] = "keyword", + ["lbu"] = "keyword", + ["lhu"] = "keyword", + ["sb"] = "keyword", + ["sh"] = "keyword", + ["sw"] = "keyword", + ["addi"] = "keyword", + ["slti"] = "keyword", + ["sltiu"] = "keyword", + ["xori"] = "keyword", + ["ori"] = "keyword", + ["andi"] = "keyword", + ["slli"] = "keyword", + ["srli"] = "keyword", + ["srai"] = "keyword", + ["add"] = "keyword", + ["sub"] = "keyword", + ["sll"] = "keyword", + ["slt"] = "keyword", + ["sltu"] = "keyword", + ["xor"] = "keyword", + ["srl"] = "keyword", + ["sra"] = "keyword", + ["or"] = "keyword", + ["and"] = "keyword", + ["fence"] = "keyword", + ["fence.tso"] = "keyword", + ["pause"] = "keyword", + ["ecall"] = "keyword", + ["ebreak"] = "keyword", + + -- RV64I instructions + ["lwu"] = "keyword", + ["ld"] = "keyword", + ["sd"] = "keyword", + ["slli"] = "keyword", + ["srli"] = "keyword", + ["srai"] = "keyword", + ["addiw"] = "keyword", + ["slliw"] = "keyword", + ["srliw"] = "keyword", + ["sraiw"] = "keyword", + ["addw"] = "keyword", + ["subw"] = "keyword", + ["sllw"] = "keyword", + ["srlw"] = "keyword", + ["sraw"] = "keyword", + + -- Zifencei instructions + ["fence.i"] = "keyword", + + -- Zicsr instructions + ["csrrw"] = "keyword", + ["csrrs"] = "keyword", + ["csrrc"] = "keyword", + ["csrrwi"] = "keyword", + ["csrrsi"] = "keyword", + ["csrrci"] = "keyword", + + -- RV32M instructions + ["mul"] = "keyword", + ["mulh"] = "keyword", + ["mulhsu"] = "keyword", + ["mulhu"] = "keyword", + ["div"] = "keyword", + ["divu"] = "keyword", + ["rem"] = "keyword", + ["remu"] = "keyword", + + -- RV64M instructions + ["mulw"] = "keyword", + ["divw"] = "keyword", + ["divuw"] = "keyword", + ["remw"] = "keyword", + ["remuw"] = "keyword", + + -- RV32A instructions + ["lr.w"] = "keyword", + ["sc.w"] = "keyword", + ["amoswap.w"] = "keyword", + ["amoadd.w"] = "keyword", + ["amoxor.w"] = "keyword", + ["amoand.w"] = "keyword", + ["amoor.w"] = "keyword", + ["amomin.w"] = "keyword", + ["amomax.w"] = "keyword", + ["amominu.w"] = "keyword", + ["amomaxu.w"] = "keyword", + + -- RV64A instructions + ["lr.d"] = "keyword", + ["sc.d"] = "keyword", + ["amoswap.d"] = "keyword", + ["amoadd.d"] = "keyword", + ["amoxor.d"] = "keyword", + ["amoand.d"] = "keyword", + ["amoor.d"] = "keyword", + ["amomin.d"] = "keyword", + ["amomax.d"] = "keyword", + ["amominu.d"] = "keyword", + ["amomaxu.d"] = "keyword", + + -- RV32F instructions + ["flw"] = "keyword", + ["fsw"] = "keyword", + ["fmadd.s"] = "keyword", + ["fmsub.s"] = "keyword", + ["fnmsub.s"] = "keyword", + ["fnmadd.s"] = "keyword", + ["fadd.s"] = "keyword", + ["fsub.s"] = "keyword", + ["fmul.s"] = "keyword", + ["fdiv.s"] = "keyword", + ["fsqrt.s"] = "keyword", + ["fsgnj.s"] = "keyword", + ["fsgnjn.s"] = "keyword", + ["fsgnjx.s"] = "keyword", + ["fmin.s"] = "keyword", + ["fmax.s"] = "keyword", + ["fcvt.w.s"] = "keyword", + ["fcvt.wu.s"] = "keyword", + ["fmv.x.w"] = "keyword", + ["feq.s"] = "keyword", + ["flt.s"] = "keyword", + ["fle.s"] = "keyword", + ["fclass.s"] = "keyword", + ["fcvt.s.w"] = "keyword", + ["fcvt.s.wu"] = "keyword", + ["fmv.w.x"] = "keyword", + + -- RV64F instructions + ["fcvt.l.s"] = "keyword", + ["fcvt.lu.s"] = "keyword", + ["fcvt.s.l"] = "keyword", + ["fcvt.s.lu"] = "keyword", + + -- RV32D instructions + ["fld"] = "keyword", + ["fsd"] = "keyword", + ["fmadd.d"] = "keyword", + ["fmsub.d"] = "keyword", + ["fnmsub.d"] = "keyword", + ["fnmadd.d"] = "keyword", + ["fadd.d"] = "keyword", + ["fsub.d"] = "keyword", + ["fmul.d"] = "keyword", + ["fdiv.d"] = "keyword", + ["fsqrt.d"] = "keyword", + ["fsgnj.d"] = "keyword", + ["fsgnjn.d"] = "keyword", + ["fsgnjx.d"] = "keyword", + ["fmin.d"] = "keyword", + ["fmax.d"] = "keyword", + ["fcvt.s.d"] = "keyword", + ["fcvt.d.s"] = "keyword", + ["feq.d"] = "keyword", + ["flt.d"] = "keyword", + ["fle.d"] = "keyword", + ["fclass.d"] = "keyword", + ["fcvt.w.d"] = "keyword", + ["fcvt.wu.d"] = "keyword", + ["fcvt.d.w"] = "keyword", + ["fcvt.d.wu"] = "keyword", + + -- RV64D instructions + ["fcvt.l.d"] = "keyword", + ["fcvt.lu.d"] = "keyword", + ["fmv.x.d"] = "keyword", + ["fcvt.d.l"] = "keyword", + ["fcvt.d.lu"] = "keyword", + ["fmv.d.x"] = "keyword", + + -- RV32Q instructions + ["flq"] = "keyword", + ["fsq"] = "keyword", + ["fmadd.q"] = "keyword", + ["fmsub.q"] = "keyword", + ["fnmsub.q"] = "keyword", + ["fnmadd.q"] = "keyword", + ["fadd.q"] = "keyword", + ["fsub.q"] = "keyword", + ["fmul.q"] = "keyword", + ["fdiv.q"] = "keyword", + ["fsqrt.q"] = "keyword", + ["fsgnj.q"] = "keyword", + ["fsgnjn.q"] = "keyword", + ["fsgnjx.q"] = "keyword", + ["fmin.q"] = "keyword", + ["fmax.q"] = "keyword", + ["fcvt.s.q"] = "keyword", + ["fcvt.q.s"] = "keyword", + ["fcvt.d.q"] = "keyword", + ["fcvt.q.d"] = "keyword", + ["feq.q"] = "keyword", + ["flt.q"] = "keyword", + ["fle.q"] = "keyword", + ["fclass.q"] = "keyword", + ["fcvt.w.q"] = "keyword", + ["fcvt.wu.q"] = "keyword", + ["fcvt.q.w"] = "keyword", + ["fcvt.q.wu"] = "keyword", + + -- RV64Q instructions + ["fcvt.l.q"] = "keyword", + ["fcvt.lu.q"] = "keyword", + ["fcvt.q.l"] = "keyword", + ["fcvt.q.lu"] = "keyword", + + -- RV32Zfh instructions + ["flh"] = "keyword", + ["fsh"] = "keyword", + ["fmadd.h"] = "keyword", + ["fmsub.h"] = "keyword", + ["fnmsub.h"] = "keyword", + ["fnmadd.h"] = "keyword", + ["fadd.h"] = "keyword", + ["fsub.h"] = "keyword", + ["fmul.h"] = "keyword", + ["fdiv.h"] = "keyword", + ["fsqrt.h"] = "keyword", + ["fsgnj.h"] = "keyword", + ["fsgnjn.h"] = "keyword", + ["fsgnjx.h"] = "keyword", + ["fmin.h"] = "keyword", + ["fmax.h"] = "keyword", + ["fcvt.s.h"] = "keyword", + ["fcvt.h.s"] = "keyword", + ["fcvt.d.h"] = "keyword", + ["fcvt.h.d"] = "keyword", + ["fcvt.q.h"] = "keyword", + ["fcvt.h.q"] = "keyword", + ["feq.h"] = "keyword", + ["flt.h"] = "keyword", + ["fle.h"] = "keyword", + ["fclass.h"] = "keyword", + ["fcvt.w.h"] = "keyword", + ["fcvt.wu.h"] = "keyword", + ["fmv.x.h"] = "keyword", + ["fcvt.h.w"] = "keyword", + ["fcvt.h.wu"] = "keyword", + ["fmv.h.x"] = "keyword", + + -- RV64Zfh instructions + ["fcvt.l.h"] = "keyword", + ["fcvt.lu.h"] = "keyword", + ["fcvt.h.l"] = "keyword", + ["fcvt.h.lu"] = "keyword", + + -- Pesudo-instructions + ["nop"] = "keyword", + ["li"] = "keyword", + ["mv"] = "keyword", + ["not"] = "keyword", + ["neg"] = "keyword", + ["negw"] = "keyword", + ["sext.w"] = "keyword", + ["seqz"] = "keyword", + ["snez"] = "keyword", + ["sltz"] = "keyword", + ["sgtz"] = "keyword", + ["fmv.s"] = "keyword", + ["fabs.s"] = "keyword", + ["fneg.s"] = "keyword", + ["fmv.d"] = "keyword", + ["fabs.d"] = "keyword", + ["fneg.d"] = "keyword", + ["beqz"] = "keyword", + ["bnez"] = "keyword", + ["blez"] = "keyword", + ["bgez"] = "keyword", + ["bltz"] = "keyword", + ["bgtz"] = "keyword", + ["bgt"] = "keyword", + ["ble"] = "keyword", + ["bgtu"] = "keyword", + ["bleu"] = "keyword", + ["j"] = "keyword", + ["jr"] = "keyword", + ["ret"] = "keyword", + ["call"] = "keyword", + ["tail"] = "keyword", + + -- Other + [".2byte"] = "keyword2", + [".4byte"] = "keyword2", + [".8byte"] = "keyword2", + [".half"] = "keyword2", + [".word"] = "keyword2", + [".dword"] = "keyword2", + [".byte"] = "keyword2", + [".dtpreldword"] = "keyword2", + [".dtprelword"] = "keyword2", + [".sleb128"] = "keyword2", + [".uleb128"] = "keyword2", + [".asciz"] = "keyword2", + [".string"] = "keyword2", + [".incbin"] = "keyword2", + [".zero"] = "keyword2", + + [".align"] = "keyword2", + [".balign"] = "keyword2", + [".p2align"] = "keyword2", + + [".globl"] = "keyword2", + [".local"] = "keyword2", + [".equ"] = "keyword2", + + [".text"] = "keyword2", + [".data"] = "keyword2", + [".rodata"] = "keyword2", + [".bss"] = "keyword2", + [".comm"] = "keyword2", + [".common"] = "keyword2", + [".section"] = "keyword2", + + [".option"] = "keyword2", + [".macro"] = "keyword2", + [".endm"] = "keyword2", + [".file"] = "keyword2", + [".ident"] = "keyword2", + [".size"] = "keyword2", + [".type"] = "keyword2", + }, +} diff --git a/debian/extra/plugins/language_assembly_x86.lua b/debian/extra/plugins/language_assembly_x86.lua new file mode 100644 index 0000000..e6d218b --- /dev/null +++ b/debian/extra/plugins/language_assembly_x86.lua @@ -0,0 +1,2215 @@ +-- mod-version:3 +-- Support for the intel syntax x86-64 assembly +-- Simply add it to lite-xl's plugins folder (located somewhere at home/.config/lite-xl/plugins) +-- https://github.com/DMClVG + +local syntax = require "core.syntax" + +syntax.add { + name = "x86 Assembly", + files = { "%.asm$", "%.[sS]$" }, + comment = ";", + patterns = { + { pattern = ";.-\n", type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "0[bB][0-1]+%W", type = "number" }, + { pattern = "[0-1]+[bB]%W", type = "number" }, + { pattern = "0[xX]%x+", type = "number" }, + { pattern = "%x+[hH]%W", type = "number" }, + { pattern = "%d+[%d%.eE]*f?", type = "number" }, + { pattern = "%.?%d+f?", type = "number" }, + { pattern = "%%+[%a_][%w_]*", type = "keyword" }, + { pattern = "[%+%-=/%*%^%%<>!~|&%$]", type = "operator" }, + { pattern = "[%a_][%w_]*:%W", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "%.%.%a+", type = "normal" } + }, + symbols = { + -- Registers + ["rax"] = "literal", + ["eax"] = "literal", + ["ax"] = "literal", + ["ah"] = "literal", + ["al"] = "literal", + ["rbx"] = "literal", + ["ebx"] = "literal", + ["bx"] = "literal", + ["bh"] = "literal", + ["bl"] = "literal", + ["rcx"] = "literal", + ["ecx"] = "literal", + ["cx"] = "literal", + ["ch"] = "literal", + ["cl"] = "literal", + ["rdx"] = "literal", + ["edx"] = "literal", + ["dx"] = "literal", + ["dh"] = "literal", + ["dl"] = "literal", + ["rbp"] = "literal", + ["ebp"] = "literal", + ["bp"] = "literal", + ["bpl"] = "literal", + ["rsi"] = "literal", + ["esi"] = "literal", + ["si"] = "literal", + ["sil"] = "literal", + ["rdi"] = "literal", + ["edi"] = "literal", + ["di"] = "literal", + ["dil"] = "literal", + ["rip"] = "literal", + ["eip"] = "literal", + ["ip"] = "literal", + ["rsp"] = "literal", + ["esp"] = "literal", + ["sp"] = "literal", + ["spl"] = "literal", + ["cs"] = "literal", + ["ds"] = "literal", + ["es"] = "literal", + ["fs"] = "literal", + ["gs"] = "literal", + ["ss"] = "literal", + ["cr0"] = "literal", + ["cr1"] = "literal", + ["cr2"] = "literal", + ["cr3"] = "literal", + ["cr4"] = "literal", + ["dr0"] = "literal", + ["dr1"] = "literal", + ["dr2"] = "literal", + ["dr3"] = "literal", + ["dr6"] = "literal", + ["dr7"] = "literal", + ["st"] = "literal", + ["st0"] = "literal", + ["st1"] = "literal", + ["st2"] = "literal", + ["st3"] = "literal", + ["st4"] = "literal", + ["st5"] = "literal", + ["st6"] = "literal", + ["st7"] = "literal", + ["mm0"] = "literal", + ["mm1"] = "literal", + ["mm2"] = "literal", + ["mm3"] = "literal", + ["mm4"] = "literal", + ["mm5"] = "literal", + ["mm6"] = "literal", + ["mm7"] = "literal", + ["xmm0"] = "literal", + ["xmm1"] = "literal", + ["xmm2"] = "literal", + ["xmm3"] = "literal", + ["xmm4"] = "literal", + ["xmm5"] = "literal", + ["xmm6"] = "literal", + ["xmm7"] = "literal", + ["xmm8"] = "literal", + ["xmm9"] = "literal", + ["xmm10"] = "literal", + ["xmm11"] = "literal", + ["xmm12"] = "literal", + ["xmm13"] = "literal", + ["xmm14"] = "literal", + ["xmm15"] = "literal", + ["xmm16"] = "literal", + ["xmm17"] = "literal", + ["xmm18"] = "literal", + ["xmm19"] = "literal", + ["xmm20"] = "literal", + ["xmm21"] = "literal", + ["xmm22"] = "literal", + ["xmm23"] = "literal", + ["xmm24"] = "literal", + ["xmm25"] = "literal", + ["xmm26"] = "literal", + ["xmm27"] = "literal", + ["xmm28"] = "literal", + ["xmm29"] = "literal", + ["xmm30"] = "literal", + ["xmm31"] = "literal", + ["ymm0"] = "literal", + ["ymm1"] = "literal", + ["ymm2"] = "literal", + ["ymm3"] = "literal", + ["ymm4"] = "literal", + ["ymm5"] = "literal", + ["ymm6"] = "literal", + ["ymm7"] = "literal", + ["ymm8"] = "literal", + ["ymm9"] = "literal", + ["ymm10"] = "literal", + ["ymm11"] = "literal", + ["ymm12"] = "literal", + ["ymm13"] = "literal", + ["ymm14"] = "literal", + ["ymm15"] = "literal", + ["ymm16"] = "literal", + ["ymm17"] = "literal", + ["ymm18"] = "literal", + ["ymm19"] = "literal", + ["ymm20"] = "literal", + ["ymm21"] = "literal", + ["ymm22"] = "literal", + ["ymm23"] = "literal", + ["ymm24"] = "literal", + ["ymm25"] = "literal", + ["ymm26"] = "literal", + ["ymm27"] = "literal", + ["ymm28"] = "literal", + ["ymm29"] = "literal", + ["ymm30"] = "literal", + ["ymm31"] = "literal", + ["zmm0"] = "literal", + ["zmm1"] = "literal", + ["zmm2"] = "literal", + ["zmm3"] = "literal", + ["zmm4"] = "literal", + ["zmm5"] = "literal", + ["zmm6"] = "literal", + ["zmm7"] = "literal", + ["zmm8"] = "literal", + ["zmm9"] = "literal", + ["zmm10"] = "literal", + ["zmm11"] = "literal", + ["zmm12"] = "literal", + ["zmm13"] = "literal", + ["zmm14"] = "literal", + ["zmm15"] = "literal", + ["zmm16"] = "literal", + ["zmm17"] = "literal", + ["zmm18"] = "literal", + ["zmm19"] = "literal", + ["zmm20"] = "literal", + ["zmm21"] = "literal", + ["zmm22"] = "literal", + ["zmm23"] = "literal", + ["zmm24"] = "literal", + ["zmm25"] = "literal", + ["zmm26"] = "literal", + ["zmm27"] = "literal", + ["zmm28"] = "literal", + ["zmm29"] = "literal", + ["zmm30"] = "literal", + ["zmm31"] = "literal", + ["r8"] = "literal", + ["r8d"] = "literal", + ["r8w"] = "literal", + ["r8b"] = "literal", + ["r9"] = "literal", + ["r9d"] = "literal", + ["r9w"] = "literal", + ["r9b"] = "literal", + ["r10"] = "literal", + ["r10d"] = "literal", + ["r10w"] = "literal", + ["r10b"] = "literal", + ["r11"] = "literal", + ["r11d"] = "literal", + ["r11w"] = "literal", + ["r11b"] = "literal", + ["r12"] = "literal", + ["r12d"] = "literal", + ["r12w"] = "literal", + ["r12b"] = "literal", + ["r13"] = "literal", + ["r13d"] = "literal", + ["r13w"] = "literal", + ["r13b"] = "literal", + ["r14"] = "literal", + ["r14d"] = "literal", + ["r14w"] = "literal", + ["r14b"] = "literal", + ["r15"] = "literal", + ["r15d"] = "literal", + ["r15w"] = "literal", + ["r15b"] = "literal", + + -- Instructions + ["aaa"] = "keyword", + ["aad"] = "keyword", + ["aam"] = "keyword", + ["aas"] = "keyword", + ["adc"] = "keyword", + ["adcx"] = "keyword", + ["add"] = "keyword", + ["addpd"] = "keyword", + ["addps"] = "keyword", + ["addsd"] = "keyword", + ["addss"] = "keyword", + ["addsubpd"] = "keyword", + ["addsubps"] = "keyword", + ["adox"] = "keyword", + ["aesdec"] = "keyword", + ["aesdeclast"] = "keyword", + ["aesenc"] = "keyword", + ["aesenclast"] = "keyword", + ["aesimc"] = "keyword", + ["aeskeygenassist"] = "keyword", + ["and"] = "keyword", + ["andn"] = "keyword", + ["andnpd"] = "keyword", + ["andnps"] = "keyword", + ["andpd"] = "keyword", + ["andps"] = "keyword", + ["arpl"] = "keyword", + ["bb0_reset"] = "keyword", + ["bb1_reset"] = "keyword", + ["bextr"] = "keyword", + ["blcfill"] = "keyword", + ["blci"] = "keyword", + ["blcic"] = "keyword", + ["blcmsk"] = "keyword", + ["blcs"] = "keyword", + ["blendpd"] = "keyword", + ["blendps"] = "keyword", + ["blendvpd"] = "keyword", + ["blendvps"] = "keyword", + ["blsfill"] = "keyword", + ["blsi"] = "keyword", + ["blsic"] = "keyword", + ["blsmsk"] = "keyword", + ["blsr"] = "keyword", + ["bndcl"] = "keyword", + ["bndcn"] = "keyword", + ["bndcu"] = "keyword", + ["bndldx"] = "keyword", + ["bndmk"] = "keyword", + ["bndmov"] = "keyword", + ["bndstx"] = "keyword", + ["bound"] = "keyword", + ["bsf"] = "keyword", + ["bsr"] = "keyword", + ["bswap"] = "keyword", + ["bt"] = "keyword", + ["btc"] = "keyword", + ["btr"] = "keyword", + ["bts"] = "keyword", + ["bzhi"] = "keyword", + ["call"] = "keyword", + ["cbw"] = "keyword", + ["cdq"] = "keyword", + ["cdqe"] = "keyword", + ["clac"] = "keyword", + ["clc"] = "keyword", + ["cld"] = "keyword", + ["clflush"] = "keyword", + ["clflushopt"] = "keyword", + ["clgi"] = "keyword", + ["cli"] = "keyword", + ["clts"] = "keyword", + ["clwb"] = "keyword", + ["clzero"] = "keyword", + ["cmc"] = "keyword", + ["cmova"] = "keyword", + ["cmovae"] = "keyword", + ["cmovb"] = "keyword", + ["cmovbe"] = "keyword", + ["cmovc"] = "keyword", + ["cmove"] = "keyword", + ["cmovg"] = "keyword", + ["cmovge"] = "keyword", + ["cmovl"] = "keyword", + ["cmovle"] = "keyword", + ["cmovna"] = "keyword", + ["cmovnae"] = "keyword", + ["cmovnb"] = "keyword", + ["cmovnbe"] = "keyword", + ["cmovnc"] = "keyword", + ["cmovne"] = "keyword", + ["cmovng"] = "keyword", + ["cmovnge"] = "keyword", + ["cmovnl"] = "keyword", + ["cmovnle"] = "keyword", + ["cmovno"] = "keyword", + ["cmovnp"] = "keyword", + ["cmovns"] = "keyword", + ["cmovnz"] = "keyword", + ["cmovo"] = "keyword", + ["cmovp"] = "keyword", + ["cmovpe"] = "keyword", + ["cmovpo"] = "keyword", + ["cmovs"] = "keyword", + ["cmovz"] = "keyword", + ["cmp"] = "keyword", + ["cmpeqpd"] = "keyword", + ["cmpeqps"] = "keyword", + ["cmpeqsd"] = "keyword", + ["cmpeqss"] = "keyword", + ["cmplepd"] = "keyword", + ["cmpleps"] = "keyword", + ["cmplesd"] = "keyword", + ["cmpless"] = "keyword", + ["cmpltpd"] = "keyword", + ["cmpltps"] = "keyword", + ["cmpltsd"] = "keyword", + ["cmpltss"] = "keyword", + ["cmpneqpd"] = "keyword", + ["cmpneqps"] = "keyword", + ["cmpneqsd"] = "keyword", + ["cmpneqss"] = "keyword", + ["cmpnlepd"] = "keyword", + ["cmpnleps"] = "keyword", + ["cmpnlesd"] = "keyword", + ["cmpnless"] = "keyword", + ["cmpnltpd"] = "keyword", + ["cmpnltps"] = "keyword", + ["cmpnltsd"] = "keyword", + ["cmpnltss"] = "keyword", + ["cmpordpd"] = "keyword", + ["cmpordps"] = "keyword", + ["cmpordsd"] = "keyword", + ["cmpordss"] = "keyword", + ["cmppd"] = "keyword", + ["cmpps"] = "keyword", + ["cmps"] = "keyword", + ["cmpsb"] = "keyword", + ["cmpsd"] = "keyword", + ["cmpsq"] = "keyword", + ["cmpss"] = "keyword", + ["cmpsw"] = "keyword", + ["cmpunordpd"] = "keyword", + ["cmpunordps"] = "keyword", + ["cmpunordsd"] = "keyword", + ["cmpunordss"] = "keyword", + ["cmpxchg"] = "keyword", + ["cmpxchg16b"] = "keyword", + ["cmpxchg486"] = "keyword", + ["cmpxchg8b"] = "keyword", + ["comisd"] = "keyword", + ["comiss"] = "keyword", + ["cpu_read"] = "keyword", + ["cpu_write"] = "keyword", + ["cpuid"] = "keyword", + ["cqo"] = "keyword", + ["crc32"] = "keyword", + ["cvtdq2pd"] = "keyword", + ["cvtdq2ps"] = "keyword", + ["cvtpd2dq"] = "keyword", + ["cvtpd2pi"] = "keyword", + ["cvtpd2ps"] = "keyword", + ["cvtpi2pd"] = "keyword", + ["cvtpi2ps"] = "keyword", + ["cvtps2dq"] = "keyword", + ["cvtps2pd"] = "keyword", + ["cvtps2pi"] = "keyword", + ["cvtsd2si"] = "keyword", + ["cvtsd2ss"] = "keyword", + ["cvtsi2sd"] = "keyword", + ["cvtsi2ss"] = "keyword", + ["cvtss2sd"] = "keyword", + ["cvtss2si"] = "keyword", + ["cvttpd2dq"] = "keyword", + ["cvttpd2pi"] = "keyword", + ["cvttps2dq"] = "keyword", + ["cvttps2pi"] = "keyword", + ["cvttsd2si"] = "keyword", + ["cvttss2si"] = "keyword", + ["cwd"] = "keyword", + ["cwde"] = "keyword", + ["daa"] = "keyword", + ["das"] = "keyword", + ["dec"] = "keyword", + ["div"] = "keyword", + ["divpd"] = "keyword", + ["divps"] = "keyword", + ["divsd"] = "keyword", + ["divss"] = "keyword", + ["dmint"] = "keyword", + ["dppd"] = "keyword", + ["dpps"] = "keyword", + ["emms"] = "keyword", + ["enter"] = "keyword", + ["extractps"] = "keyword", + ["extrq"] = "keyword", + ["f2xm1"] = "keyword", + ["fabs"] = "keyword", + ["fadd"] = "keyword", + ["faddp"] = "keyword", + ["fbld"] = "keyword", + ["fbstp"] = "keyword", + ["fchs"] = "keyword", + ["fclex"] = "keyword", + ["fcmovb"] = "keyword", + ["fcmovbe"] = "keyword", + ["fcmove"] = "keyword", + ["fcmovnb"] = "keyword", + ["fcmovnbe"] = "keyword", + ["fcmovne"] = "keyword", + ["fcmovnu"] = "keyword", + ["fcmovu"] = "keyword", + ["fcom"] = "keyword", + ["fcomi"] = "keyword", + ["fcomip"] = "keyword", + ["fcomp"] = "keyword", + ["fcompp"] = "keyword", + ["fcos"] = "keyword", + ["fdecstp"] = "keyword", + ["fdisi"] = "keyword", + ["fdiv"] = "keyword", + ["fdivp"] = "keyword", + ["fdivr"] = "keyword", + ["fdivrp"] = "keyword", + ["femms"] = "keyword", + ["feni"] = "keyword", + ["ffree"] = "keyword", + ["ffreep"] = "keyword", + ["fiadd"] = "keyword", + ["ficom"] = "keyword", + ["ficomp"] = "keyword", + ["fidiv"] = "keyword", + ["fidivr"] = "keyword", + ["fild"] = "keyword", + ["fimul"] = "keyword", + ["fincstp"] = "keyword", + ["finit"] = "keyword", + ["fist"] = "keyword", + ["fistp"] = "keyword", + ["fisttp"] = "keyword", + ["fisub"] = "keyword", + ["fisubr"] = "keyword", + ["fld"] = "keyword", + ["fld1"] = "keyword", + ["fldcw"] = "keyword", + ["fldenv"] = "keyword", + ["fldl2e"] = "keyword", + ["fldl2t"] = "keyword", + ["fldlg2"] = "keyword", + ["fldln2"] = "keyword", + ["fldpi"] = "keyword", + ["fldz"] = "keyword", + ["fmul"] = "keyword", + ["fmulp"] = "keyword", + ["fnclex"] = "keyword", + ["fndisi"] = "keyword", + ["fneni"] = "keyword", + ["fninit"] = "keyword", + ["fnop"] = "keyword", + ["fnsave"] = "keyword", + ["fnstcw"] = "keyword", + ["fnstenv"] = "keyword", + ["fnstsw"] = "keyword", + ["fnwait"] = "keyword", + ["fpatan"] = "keyword", + ["fprem"] = "keyword", + ["fprem1"] = "keyword", + ["fptan"] = "keyword", + ["frndint"] = "keyword", + ["frstor"] = "keyword", + ["fsave"] = "keyword", + ["fscale"] = "keyword", + ["fsetpm"] = "keyword", + ["fsin"] = "keyword", + ["fsincos"] = "keyword", + ["fsqrt"] = "keyword", + ["fst"] = "keyword", + ["fstcw"] = "keyword", + ["fstenv"] = "keyword", + ["fstp"] = "keyword", + ["fstsw"] = "keyword", + ["fsub"] = "keyword", + ["fsubp"] = "keyword", + ["fsubr"] = "keyword", + ["fsubrp"] = "keyword", + ["ftst"] = "keyword", + ["fucom"] = "keyword", + ["fucomi"] = "keyword", + ["fucomip"] = "keyword", + ["fucomp"] = "keyword", + ["fucompp"] = "keyword", + ["fwait"] = "keyword", + ["fxam"] = "keyword", + ["fxch"] = "keyword", + ["fxrstor"] = "keyword", + ["fxrstor64"] = "keyword", + ["fxsave"] = "keyword", + ["fxsave64"] = "keyword", + ["fxtract"] = "keyword", + ["fyl2x"] = "keyword", + ["fyl2xp1"] = "keyword", + ["getsec"] = "keyword", + ["haddpd"] = "keyword", + ["haddps"] = "keyword", + ["hint_nop0"] = "keyword", + ["hint_nop1"] = "keyword", + ["hint_nop10"] = "keyword", + ["hint_nop11"] = "keyword", + ["hint_nop12"] = "keyword", + ["hint_nop13"] = "keyword", + ["hint_nop14"] = "keyword", + ["hint_nop15"] = "keyword", + ["hint_nop16"] = "keyword", + ["hint_nop17"] = "keyword", + ["hint_nop18"] = "keyword", + ["hint_nop19"] = "keyword", + ["hint_nop2"] = "keyword", + ["hint_nop20"] = "keyword", + ["hint_nop21"] = "keyword", + ["hint_nop22"] = "keyword", + ["hint_nop23"] = "keyword", + ["hint_nop24"] = "keyword", + ["hint_nop25"] = "keyword", + ["hint_nop26"] = "keyword", + ["hint_nop27"] = "keyword", + ["hint_nop28"] = "keyword", + ["hint_nop29"] = "keyword", + ["hint_nop3"] = "keyword", + ["hint_nop30"] = "keyword", + ["hint_nop31"] = "keyword", + ["hint_nop32"] = "keyword", + ["hint_nop33"] = "keyword", + ["hint_nop34"] = "keyword", + ["hint_nop35"] = "keyword", + ["hint_nop36"] = "keyword", + ["hint_nop37"] = "keyword", + ["hint_nop38"] = "keyword", + ["hint_nop39"] = "keyword", + ["hint_nop4"] = "keyword", + ["hint_nop40"] = "keyword", + ["hint_nop41"] = "keyword", + ["hint_nop42"] = "keyword", + ["hint_nop43"] = "keyword", + ["hint_nop44"] = "keyword", + ["hint_nop45"] = "keyword", + ["hint_nop46"] = "keyword", + ["hint_nop47"] = "keyword", + ["hint_nop48"] = "keyword", + ["hint_nop49"] = "keyword", + ["hint_nop5"] = "keyword", + ["hint_nop50"] = "keyword", + ["hint_nop51"] = "keyword", + ["hint_nop52"] = "keyword", + ["hint_nop53"] = "keyword", + ["hint_nop54"] = "keyword", + ["hint_nop55"] = "keyword", + ["hint_nop56"] = "keyword", + ["hint_nop57"] = "keyword", + ["hint_nop58"] = "keyword", + ["hint_nop59"] = "keyword", + ["hint_nop6"] = "keyword", + ["hint_nop60"] = "keyword", + ["hint_nop61"] = "keyword", + ["hint_nop62"] = "keyword", + ["hint_nop63"] = "keyword", + ["hint_nop7"] = "keyword", + ["hint_nop8"] = "keyword", + ["hint_nop9"] = "keyword", + ["hlt"] = "keyword", + ["hsubpd"] = "keyword", + ["hsubps"] = "keyword", + ["ibts"] = "keyword", + ["icebp"] = "keyword", + ["idiv"] = "keyword", + ["imul"] = "keyword", + ["in"] = "keyword", + ["inc"] = "keyword", + ["ins"] = "keyword", + ["insb"] = "keyword", + ["insd"] = "keyword", + ["insertps"] = "keyword", + ["insertq"] = "keyword", + ["insw"] = "keyword", + ["int"] = "keyword", + ["int01"] = "keyword", + ["int03"] = "keyword", + ["int1"] = "keyword", + ["int3"] = "keyword", + ["into"] = "keyword", + ["invd"] = "keyword", + ["invept"] = "keyword", + ["invlpg"] = "keyword", + ["invlpga"] = "keyword", + ["invpcid"] = "keyword", + ["invvpid"] = "keyword", + ["iret"] = "keyword", + ["iretd"] = "keyword", + ["iretq"] = "keyword", + ["iretw"] = "keyword", + ["ja"] = "keyword", + ["jae"] = "keyword", + ["jb"] = "keyword", + ["jbe"] = "keyword", + ["jc"] = "keyword", + ["jcc"] = "keyword", + ["jcxz"] = "keyword", + ["je"] = "keyword", + ["jecxz"] = "keyword", + ["jg"] = "keyword", + ["jge"] = "keyword", + ["jl"] = "keyword", + ["jle"] = "keyword", + ["jmp"] = "keyword", + ["jmpe"] = "keyword", + ["jna"] = "keyword", + ["jnae"] = "keyword", + ["jnb"] = "keyword", + ["jnbe"] = "keyword", + ["jnc"] = "keyword", + ["jne"] = "keyword", + ["jng"] = "keyword", + ["jnge"] = "keyword", + ["jnl"] = "keyword", + ["jnle"] = "keyword", + ["jno"] = "keyword", + ["jnp"] = "keyword", + ["jns"] = "keyword", + ["jnz"] = "keyword", + ["jo"] = "keyword", + ["jp"] = "keyword", + ["jpe"] = "keyword", + ["jpo"] = "keyword", + ["jrcxz"] = "keyword", + ["js"] = "keyword", + ["jz"] = "keyword", + ["kaddb"] = "keyword", + ["kaddd"] = "keyword", + ["kaddq"] = "keyword", + ["kaddw"] = "keyword", + ["kandb"] = "keyword", + ["kandd"] = "keyword", + ["kandnb"] = "keyword", + ["kandnd"] = "keyword", + ["kandnq"] = "keyword", + ["kandnw"] = "keyword", + ["kandq"] = "keyword", + ["kandw"] = "keyword", + ["kmovb"] = "keyword", + ["kmovd"] = "keyword", + ["kmovq"] = "keyword", + ["kmovw"] = "keyword", + ["knotb"] = "keyword", + ["knotd"] = "keyword", + ["knotq"] = "keyword", + ["knotw"] = "keyword", + ["korb"] = "keyword", + ["kord"] = "keyword", + ["korq"] = "keyword", + ["kortestb"] = "keyword", + ["kortestd"] = "keyword", + ["kortestq"] = "keyword", + ["kortestw"] = "keyword", + ["korw"] = "keyword", + ["kshiftlb"] = "keyword", + ["kshiftld"] = "keyword", + ["kshiftlq"] = "keyword", + ["kshiftlw"] = "keyword", + ["kshiftrb"] = "keyword", + ["kshiftrd"] = "keyword", + ["kshiftrq"] = "keyword", + ["kshiftrw"] = "keyword", + ["ktestb"] = "keyword", + ["ktestd"] = "keyword", + ["ktestq"] = "keyword", + ["ktestw"] = "keyword", + ["kunpckbw"] = "keyword", + ["kunpckdq"] = "keyword", + ["kunpckwd"] = "keyword", + ["kxnorb"] = "keyword", + ["kxnord"] = "keyword", + ["kxnorq"] = "keyword", + ["kxnorw"] = "keyword", + ["kxorb"] = "keyword", + ["kxord"] = "keyword", + ["kxorq"] = "keyword", + ["kxorw"] = "keyword", + ["lahf"] = "keyword", + ["lar"] = "keyword", + ["lddqu"] = "keyword", + ["ldmxcsr"] = "keyword", + ["lds"] = "keyword", + ["lea"] = "keyword", + ["leave"] = "keyword", + ["les"] = "keyword", + ["lfence"] = "keyword", + ["lfs"] = "keyword", + ["lgdt"] = "keyword", + ["lgs"] = "keyword", + ["lidt"] = "keyword", + ["lldt"] = "keyword", + ["llwpcb"] = "keyword", + ["lmsw"] = "keyword", + ["loadall"] = "keyword", + ["loadall286"] = "keyword", + ["lock"] = "keyword", + ["lods"] = "keyword", + ["lodsb"] = "keyword", + ["lodsd"] = "keyword", + ["lodsq"] = "keyword", + ["lodsw"] = "keyword", + ["loop"] = "keyword", + ["loope"] = "keyword", + ["loopne"] = "keyword", + ["loopnz"] = "keyword", + ["loopz"] = "keyword", + ["lsl"] = "keyword", + ["lss"] = "keyword", + ["ltr"] = "keyword", + ["lwpins"] = "keyword", + ["lwpval"] = "keyword", + ["lzcnt"] = "keyword", + ["maskmovdqu"] = "keyword", + ["maskmovq"] = "keyword", + ["maxpd"] = "keyword", + ["maxps"] = "keyword", + ["maxsd"] = "keyword", + ["maxss"] = "keyword", + ["mfence"] = "keyword", + ["minpd"] = "keyword", + ["minps"] = "keyword", + ["minsd"] = "keyword", + ["minss"] = "keyword", + ["monitor"] = "keyword", + ["monitorx"] = "keyword", + ["montmul"] = "keyword", + ["mov"] = "keyword", + ["movapd"] = "keyword", + ["movaps"] = "keyword", + ["movbe"] = "keyword", + ["movd"] = "keyword", + ["movddup"] = "keyword", + ["movdq2q"] = "keyword", + ["movdqa"] = "keyword", + ["movdqu"] = "keyword", + ["movhlps"] = "keyword", + ["movhpd"] = "keyword", + ["movhps"] = "keyword", + ["movlhps"] = "keyword", + ["movlpd"] = "keyword", + ["movlps"] = "keyword", + ["movmskpd"] = "keyword", + ["movmskps"] = "keyword", + ["movntdq"] = "keyword", + ["movntdqa"] = "keyword", + ["movnti"] = "keyword", + ["movntpd"] = "keyword", + ["movntps"] = "keyword", + ["movntq"] = "keyword", + ["movntsd"] = "keyword", + ["movntss"] = "keyword", + ["movq"] = "keyword", + ["movq2dq"] = "keyword", + ["movs"] = "keyword", + ["movsb"] = "keyword", + ["movsd"] = "keyword", + ["movshdup"] = "keyword", + ["movsldup"] = "keyword", + ["movsq"] = "keyword", + ["movss"] = "keyword", + ["movsw"] = "keyword", + ["movsx"] = "keyword", + ["movsxd"] = "keyword", + ["movupd"] = "keyword", + ["movups"] = "keyword", + ["movzx"] = "keyword", + ["mpsadbw"] = "keyword", + ["mul"] = "keyword", + ["mulpd"] = "keyword", + ["mulps"] = "keyword", + ["mulsd"] = "keyword", + ["mulss"] = "keyword", + ["mulx"] = "keyword", + ["mwait"] = "keyword", + ["mwaitx"] = "keyword", + ["neg"] = "keyword", + ["nop"] = "keyword", + ["not"] = "keyword", + ["or"] = "keyword", + ["orpd"] = "keyword", + ["orps"] = "keyword", + ["out"] = "keyword", + ["outs"] = "keyword", + ["outsb"] = "keyword", + ["outsd"] = "keyword", + ["outsw"] = "keyword", + ["pabsb"] = "keyword", + ["pabsd"] = "keyword", + ["pabsw"] = "keyword", + ["packssdw"] = "keyword", + ["packsswb"] = "keyword", + ["packusdw"] = "keyword", + ["packuswb"] = "keyword", + ["paddb"] = "keyword", + ["paddd"] = "keyword", + ["paddq"] = "keyword", + ["paddsb"] = "keyword", + ["paddsiw"] = "keyword", + ["paddsw"] = "keyword", + ["paddusb"] = "keyword", + ["paddusw"] = "keyword", + ["paddw"] = "keyword", + ["palignr"] = "keyword", + ["pand"] = "keyword", + ["pandn"] = "keyword", + ["pause"] = "keyword", + ["paveb"] = "keyword", + ["pavgb"] = "keyword", + ["pavgusb"] = "keyword", + ["pavgw"] = "keyword", + ["pblendvb"] = "keyword", + ["pblendw"] = "keyword", + ["pclmulhqhqdq"] = "keyword", + ["pclmulhqlqdq"] = "keyword", + ["pclmullqhqdq"] = "keyword", + ["pclmullqlqdq"] = "keyword", + ["pclmulqdq"] = "keyword", + ["pcmpeqb"] = "keyword", + ["pcmpeqd"] = "keyword", + ["pcmpeqq"] = "keyword", + ["pcmpeqw"] = "keyword", + ["pcmpestri"] = "keyword", + ["pcmpestrm"] = "keyword", + ["pcmpgtb"] = "keyword", + ["pcmpgtd"] = "keyword", + ["pcmpgtq"] = "keyword", + ["pcmpgtw"] = "keyword", + ["pcmpistri"] = "keyword", + ["pcmpistrm"] = "keyword", + ["pcommit"] = "keyword", + ["pdep"] = "keyword", + ["pdistib"] = "keyword", + ["pext"] = "keyword", + ["pextrb"] = "keyword", + ["pextrd"] = "keyword", + ["pextrq"] = "keyword", + ["pextrw"] = "keyword", + ["pf2id"] = "keyword", + ["pf2iw"] = "keyword", + ["pfacc"] = "keyword", + ["pfadd"] = "keyword", + ["pfcmpeq"] = "keyword", + ["pfcmpge"] = "keyword", + ["pfcmpgt"] = "keyword", + ["pfmax"] = "keyword", + ["pfmin"] = "keyword", + ["pfmul"] = "keyword", + ["pfnacc"] = "keyword", + ["pfpnacc"] = "keyword", + ["pfrcp"] = "keyword", + ["pfrcpit1"] = "keyword", + ["pfrcpit2"] = "keyword", + ["pfrcpv"] = "keyword", + ["pfrsqit1"] = "keyword", + ["pfrsqrt"] = "keyword", + ["pfrsqrtv"] = "keyword", + ["pfsub"] = "keyword", + ["pfsubr"] = "keyword", + ["phaddd"] = "keyword", + ["phaddsw"] = "keyword", + ["phaddw"] = "keyword", + ["phminposuw"] = "keyword", + ["phsubd"] = "keyword", + ["phsubsw"] = "keyword", + ["phsubw"] = "keyword", + ["pi2fd"] = "keyword", + ["pi2fw"] = "keyword", + ["pinsrb"] = "keyword", + ["pinsrd"] = "keyword", + ["pinsrq"] = "keyword", + ["pinsrw"] = "keyword", + ["pmachriw"] = "keyword", + ["pmaddubsw"] = "keyword", + ["pmaddwd"] = "keyword", + ["pmagw"] = "keyword", + ["pmaxsb"] = "keyword", + ["pmaxsd"] = "keyword", + ["pmaxsw"] = "keyword", + ["pmaxub"] = "keyword", + ["pmaxud"] = "keyword", + ["pmaxuw"] = "keyword", + ["pminsb"] = "keyword", + ["pminsd"] = "keyword", + ["pminsw"] = "keyword", + ["pminub"] = "keyword", + ["pminud"] = "keyword", + ["pminuw"] = "keyword", + ["pmovmskb"] = "keyword", + ["pmovsxbd"] = "keyword", + ["pmovsxbq"] = "keyword", + ["pmovsxbw"] = "keyword", + ["pmovsxdq"] = "keyword", + ["pmovsxwd"] = "keyword", + ["pmovsxwq"] = "keyword", + ["pmovzxbd"] = "keyword", + ["pmovzxbq"] = "keyword", + ["pmovzxbw"] = "keyword", + ["pmovzxdq"] = "keyword", + ["pmovzxwd"] = "keyword", + ["pmovzxwq"] = "keyword", + ["pmuldq"] = "keyword", + ["pmulhriw"] = "keyword", + ["pmulhrsw"] = "keyword", + ["pmulhrw"] = "keyword", + ["pmulhrwa"] = "keyword", + ["pmulhrwc"] = "keyword", + ["pmulhuw"] = "keyword", + ["pmulhw"] = "keyword", + ["pmulld"] = "keyword", + ["pmullw"] = "keyword", + ["pmuludq"] = "keyword", + ["pmvgezb"] = "keyword", + ["pmvlzb"] = "keyword", + ["pmvnzb"] = "keyword", + ["pmvzb"] = "keyword", + ["pop"] = "keyword", + ["popa"] = "keyword", + ["popad"] = "keyword", + ["popaw"] = "keyword", + ["popcnt"] = "keyword", + ["popf"] = "keyword", + ["popfd"] = "keyword", + ["popfq"] = "keyword", + ["popfw"] = "keyword", + ["por"] = "keyword", + ["prefetch"] = "keyword", + ["prefetchnta"] = "keyword", + ["prefetcht0"] = "keyword", + ["prefetcht1"] = "keyword", + ["prefetcht2"] = "keyword", + ["prefetchw"] = "keyword", + ["prefetchwt1"] = "keyword", + ["psadbw"] = "keyword", + ["pshufb"] = "keyword", + ["pshufd"] = "keyword", + ["pshufhw"] = "keyword", + ["pshuflw"] = "keyword", + ["pshufw"] = "keyword", + ["psignb"] = "keyword", + ["psignd"] = "keyword", + ["psignw"] = "keyword", + ["pslld"] = "keyword", + ["pslldq"] = "keyword", + ["psllq"] = "keyword", + ["psllw"] = "keyword", + ["psrad"] = "keyword", + ["psraw"] = "keyword", + ["psrld"] = "keyword", + ["psrldq"] = "keyword", + ["psrlq"] = "keyword", + ["psrlw"] = "keyword", + ["psubb"] = "keyword", + ["psubd"] = "keyword", + ["psubq"] = "keyword", + ["psubsb"] = "keyword", + ["psubsiw"] = "keyword", + ["psubsw"] = "keyword", + ["psubusb"] = "keyword", + ["psubusw"] = "keyword", + ["psubw"] = "keyword", + ["pswapd"] = "keyword", + ["ptest"] = "keyword", + ["punpckhbw"] = "keyword", + ["punpckhdq"] = "keyword", + ["punpckhqdq"] = "keyword", + ["punpckhwd"] = "keyword", + ["punpcklbw"] = "keyword", + ["punpckldq"] = "keyword", + ["punpcklqdq"] = "keyword", + ["punpcklwd"] = "keyword", + ["push"] = "keyword", + ["pusha"] = "keyword", + ["pushad"] = "keyword", + ["pushaw"] = "keyword", + ["pushf"] = "keyword", + ["pushfd"] = "keyword", + ["pushfq"] = "keyword", + ["pushfw"] = "keyword", + ["pxor"] = "keyword", + ["rcl"] = "keyword", + ["rcpps"] = "keyword", + ["rcpss"] = "keyword", + ["rcr"] = "keyword", + ["rdfsbase"] = "keyword", + ["rdgsbase"] = "keyword", + ["rdm"] = "keyword", + ["rdmsr"] = "keyword", + ["rdpid"] = "keyword", + ["rdpkru"] = "keyword", + ["rdpmc"] = "keyword", + ["rdrand"] = "keyword", + ["rdseed"] = "keyword", + ["rdshr"] = "keyword", + ["rdtsc"] = "keyword", + ["rdtscp"] = "keyword", + ["rep"] = "keyword", + ["repe"] = "keyword", + ["repne"] = "keyword", + ["repnz"] = "keyword", + ["repz"] = "keyword", + ["ret"] = "keyword", + ["retf"] = "keyword", + ["retn"] = "keyword", + ["rol"] = "keyword", + ["ror"] = "keyword", + ["rorx"] = "keyword", + ["roundpd"] = "keyword", + ["roundps"] = "keyword", + ["roundsd"] = "keyword", + ["roundss"] = "keyword", + ["roxr"] = "keyword", + ["rsdc"] = "keyword", + ["rsldt"] = "keyword", + ["rsm"] = "keyword", + ["rsqrtps"] = "keyword", + ["rsqrtss"] = "keyword", + ["rsts"] = "keyword", + ["sahf"] = "keyword", + ["sal"] = "keyword", + ["salc"] = "keyword", + ["sar"] = "keyword", + ["sarx"] = "keyword", + ["sbb"] = "keyword", + ["scas"] = "keyword", + ["scasb"] = "keyword", + ["scasd"] = "keyword", + ["scasq"] = "keyword", + ["scasw"] = "keyword", + ["seta"] = "keyword", + ["setae"] = "keyword", + ["setb"] = "keyword", + ["setbe"] = "keyword", + ["setc"] = "keyword", + ["sete"] = "keyword", + ["setg"] = "keyword", + ["setge"] = "keyword", + ["setl"] = "keyword", + ["setle"] = "keyword", + ["setna"] = "keyword", + ["setnae"] = "keyword", + ["setnb"] = "keyword", + ["setnbe"] = "keyword", + ["setnc"] = "keyword", + ["setne"] = "keyword", + ["setng"] = "keyword", + ["setnge"] = "keyword", + ["setnl"] = "keyword", + ["setnle"] = "keyword", + ["setno"] = "keyword", + ["setnp"] = "keyword", + ["setns"] = "keyword", + ["setnz"] = "keyword", + ["seto"] = "keyword", + ["setp"] = "keyword", + ["setpe"] = "keyword", + ["setpo"] = "keyword", + ["sets"] = "keyword", + ["setz"] = "keyword", + ["sfence"] = "keyword", + ["sgdt"] = "keyword", + ["shl"] = "keyword", + ["shld"] = "keyword", + ["shlx"] = "keyword", + ["shr"] = "keyword", + ["shrd"] = "keyword", + ["shrx"] = "keyword", + ["shufpd"] = "keyword", + ["shufps"] = "keyword", + ["sidt"] = "keyword", + ["skinit"] = "keyword", + ["sldt"] = "keyword", + ["slwpcb"] = "keyword", + ["smi"] = "keyword", + ["smint"] = "keyword", + ["smintold"] = "keyword", + ["smsw"] = "keyword", + ["sqrtpd"] = "keyword", + ["sqrtps"] = "keyword", + ["sqrtsd"] = "keyword", + ["sqrtss"] = "keyword", + ["stac"] = "keyword", + ["stc"] = "keyword", + ["std"] = "keyword", + ["stgi"] = "keyword", + ["sti"] = "keyword", + ["stmxcsr"] = "keyword", + ["stos"] = "keyword", + ["stosb"] = "keyword", + ["stosd"] = "keyword", + ["stosq"] = "keyword", + ["stosw"] = "keyword", + ["str"] = "keyword", + ["sub"] = "keyword", + ["subpd"] = "keyword", + ["subps"] = "keyword", + ["subsd"] = "keyword", + ["subss"] = "keyword", + ["svdc"] = "keyword", + ["svldt"] = "keyword", + ["svts"] = "keyword", + ["swapgs"] = "keyword", + ["syscall"] = "keyword", + ["sysenter"] = "keyword", + ["sysexit"] = "keyword", + ["sysret"] = "keyword", + ["t1mskc"] = "keyword", + ["test"] = "keyword", + ["tzcnt"] = "keyword", + ["tzmsk"] = "keyword", + ["ucomisd"] = "keyword", + ["ucomiss"] = "keyword", + ["ud0"] = "keyword", + ["ud1"] = "keyword", + ["ud2"] = "keyword", + ["ud2a"] = "keyword", + ["ud2b"] = "keyword", + ["umov"] = "keyword", + ["unpckhpd"] = "keyword", + ["unpckhps"] = "keyword", + ["unpcklpd"] = "keyword", + ["unpcklps"] = "keyword", + ["vaddpd"] = "keyword", + ["vaddps"] = "keyword", + ["vaddsd"] = "keyword", + ["vaddss"] = "keyword", + ["vaddsubpd"] = "keyword", + ["vaddsubps"] = "keyword", + ["vaesdec"] = "keyword", + ["vaesdeclast"] = "keyword", + ["vaesenc"] = "keyword", + ["vaesenclast"] = "keyword", + ["vaesimc"] = "keyword", + ["vaeskeygenassist"] = "keyword", + ["valignd"] = "keyword", + ["valignq"] = "keyword", + ["vandnpd"] = "keyword", + ["vandnps"] = "keyword", + ["vandpd"] = "keyword", + ["vandps"] = "keyword", + ["vblendmpd"] = "keyword", + ["vblendmps"] = "keyword", + ["vblendpd"] = "keyword", + ["vblendps"] = "keyword", + ["vblendvpd"] = "keyword", + ["vblendvps"] = "keyword", + ["vbroadcastb"] = "keyword", + ["vbroadcastd"] = "keyword", + ["vbroadcastf128"] = "keyword", + ["vbroadcastf32x2"] = "keyword", + ["vbroadcastf32x4"] = "keyword", + ["vbroadcastf32x8"] = "keyword", + ["vbroadcastf64x2"] = "keyword", + ["vbroadcastf64x4"] = "keyword", + ["vbroadcasti128"] = "keyword", + ["vbroadcasti32x2"] = "keyword", + ["vbroadcasti32x4"] = "keyword", + ["vbroadcasti32x8"] = "keyword", + ["vbroadcasti64x2"] = "keyword", + ["vbroadcasti64x4"] = "keyword", + ["vbroadcastq"] = "keyword", + ["vbroadcastsd"] = "keyword", + ["vbroadcastss"] = "keyword", + ["vbroadcastw"] = "keyword", + ["vcmpeq_ospd"] = "keyword", + ["vcmpeq_osps"] = "keyword", + ["vcmpeq_ossd"] = "keyword", + ["vcmpeq_osss"] = "keyword", + ["vcmpeq_uqpd"] = "keyword", + ["vcmpeq_uqps"] = "keyword", + ["vcmpeq_uqsd"] = "keyword", + ["vcmpeq_uqss"] = "keyword", + ["vcmpeq_uspd"] = "keyword", + ["vcmpeq_usps"] = "keyword", + ["vcmpeq_ussd"] = "keyword", + ["vcmpeq_usss"] = "keyword", + ["vcmpeqpd"] = "keyword", + ["vcmpeqps"] = "keyword", + ["vcmpeqsd"] = "keyword", + ["vcmpeqss"] = "keyword", + ["vcmpfalse_oqpd"] = "keyword", + ["vcmpfalse_oqps"] = "keyword", + ["vcmpfalse_oqsd"] = "keyword", + ["vcmpfalse_oqss"] = "keyword", + ["vcmpfalse_ospd"] = "keyword", + ["vcmpfalse_osps"] = "keyword", + ["vcmpfalse_ossd"] = "keyword", + ["vcmpfalse_osss"] = "keyword", + ["vcmpfalsepd"] = "keyword", + ["vcmpfalseps"] = "keyword", + ["vcmpfalsesd"] = "keyword", + ["vcmpfalsess"] = "keyword", + ["vcmpge_oqpd"] = "keyword", + ["vcmpge_oqps"] = "keyword", + ["vcmpge_oqsd"] = "keyword", + ["vcmpge_oqss"] = "keyword", + ["vcmpge_ospd"] = "keyword", + ["vcmpge_osps"] = "keyword", + ["vcmpge_ossd"] = "keyword", + ["vcmpge_osss"] = "keyword", + ["vcmpgepd"] = "keyword", + ["vcmpgeps"] = "keyword", + ["vcmpgesd"] = "keyword", + ["vcmpgess"] = "keyword", + ["vcmpgt_oqpd"] = "keyword", + ["vcmpgt_oqps"] = "keyword", + ["vcmpgt_oqsd"] = "keyword", + ["vcmpgt_oqss"] = "keyword", + ["vcmpgt_ospd"] = "keyword", + ["vcmpgt_osps"] = "keyword", + ["vcmpgt_ossd"] = "keyword", + ["vcmpgt_osss"] = "keyword", + ["vcmpgtpd"] = "keyword", + ["vcmpgtps"] = "keyword", + ["vcmpgtsd"] = "keyword", + ["vcmpgtss"] = "keyword", + ["vcmple_oqpd"] = "keyword", + ["vcmple_oqps"] = "keyword", + ["vcmple_oqsd"] = "keyword", + ["vcmple_oqss"] = "keyword", + ["vcmple_ospd"] = "keyword", + ["vcmple_osps"] = "keyword", + ["vcmple_ossd"] = "keyword", + ["vcmple_osss"] = "keyword", + ["vcmplepd"] = "keyword", + ["vcmpleps"] = "keyword", + ["vcmplesd"] = "keyword", + ["vcmpless"] = "keyword", + ["vcmplt_oqpd"] = "keyword", + ["vcmplt_oqps"] = "keyword", + ["vcmplt_oqsd"] = "keyword", + ["vcmplt_oqss"] = "keyword", + ["vcmplt_ospd"] = "keyword", + ["vcmplt_osps"] = "keyword", + ["vcmplt_ossd"] = "keyword", + ["vcmplt_osss"] = "keyword", + ["vcmpltpd"] = "keyword", + ["vcmpltps"] = "keyword", + ["vcmpltsd"] = "keyword", + ["vcmpltss"] = "keyword", + ["vcmpneq_oqpd"] = "keyword", + ["vcmpneq_oqps"] = "keyword", + ["vcmpneq_oqsd"] = "keyword", + ["vcmpneq_oqss"] = "keyword", + ["vcmpneq_ospd"] = "keyword", + ["vcmpneq_osps"] = "keyword", + ["vcmpneq_ossd"] = "keyword", + ["vcmpneq_osss"] = "keyword", + ["vcmpneq_uqpd"] = "keyword", + ["vcmpneq_uqps"] = "keyword", + ["vcmpneq_uqsd"] = "keyword", + ["vcmpneq_uqss"] = "keyword", + ["vcmpneq_uspd"] = "keyword", + ["vcmpneq_usps"] = "keyword", + ["vcmpneq_ussd"] = "keyword", + ["vcmpneq_usss"] = "keyword", + ["vcmpneqpd"] = "keyword", + ["vcmpneqps"] = "keyword", + ["vcmpneqsd"] = "keyword", + ["vcmpneqss"] = "keyword", + ["vcmpnge_uqpd"] = "keyword", + ["vcmpnge_uqps"] = "keyword", + ["vcmpnge_uqsd"] = "keyword", + ["vcmpnge_uqss"] = "keyword", + ["vcmpnge_uspd"] = "keyword", + ["vcmpnge_usps"] = "keyword", + ["vcmpnge_ussd"] = "keyword", + ["vcmpnge_usss"] = "keyword", + ["vcmpngepd"] = "keyword", + ["vcmpngeps"] = "keyword", + ["vcmpngesd"] = "keyword", + ["vcmpngess"] = "keyword", + ["vcmpngt_uqpd"] = "keyword", + ["vcmpngt_uqps"] = "keyword", + ["vcmpngt_uqsd"] = "keyword", + ["vcmpngt_uqss"] = "keyword", + ["vcmpngt_uspd"] = "keyword", + ["vcmpngt_usps"] = "keyword", + ["vcmpngt_ussd"] = "keyword", + ["vcmpngt_usss"] = "keyword", + ["vcmpngtpd"] = "keyword", + ["vcmpngtps"] = "keyword", + ["vcmpngtsd"] = "keyword", + ["vcmpngtss"] = "keyword", + ["vcmpnle_uqpd"] = "keyword", + ["vcmpnle_uqps"] = "keyword", + ["vcmpnle_uqsd"] = "keyword", + ["vcmpnle_uqss"] = "keyword", + ["vcmpnle_uspd"] = "keyword", + ["vcmpnle_usps"] = "keyword", + ["vcmpnle_ussd"] = "keyword", + ["vcmpnle_usss"] = "keyword", + ["vcmpnlepd"] = "keyword", + ["vcmpnleps"] = "keyword", + ["vcmpnlesd"] = "keyword", + ["vcmpnless"] = "keyword", + ["vcmpnlt_uqpd"] = "keyword", + ["vcmpnlt_uqps"] = "keyword", + ["vcmpnlt_uqsd"] = "keyword", + ["vcmpnlt_uqss"] = "keyword", + ["vcmpnlt_uspd"] = "keyword", + ["vcmpnlt_usps"] = "keyword", + ["vcmpnlt_ussd"] = "keyword", + ["vcmpnlt_usss"] = "keyword", + ["vcmpnltpd"] = "keyword", + ["vcmpnltps"] = "keyword", + ["vcmpnltsd"] = "keyword", + ["vcmpnltss"] = "keyword", + ["vcmpord_qpd"] = "keyword", + ["vcmpord_qps"] = "keyword", + ["vcmpord_qsd"] = "keyword", + ["vcmpord_qss"] = "keyword", + ["vcmpord_spd"] = "keyword", + ["vcmpord_sps"] = "keyword", + ["vcmpord_ssd"] = "keyword", + ["vcmpord_sss"] = "keyword", + ["vcmpordpd"] = "keyword", + ["vcmpordps"] = "keyword", + ["vcmpordsd"] = "keyword", + ["vcmpordss"] = "keyword", + ["vcmppd"] = "keyword", + ["vcmpps"] = "keyword", + ["vcmpsd"] = "keyword", + ["vcmpss"] = "keyword", + ["vcmptrue_uqpd"] = "keyword", + ["vcmptrue_uqps"] = "keyword", + ["vcmptrue_uqsd"] = "keyword", + ["vcmptrue_uqss"] = "keyword", + ["vcmptrue_uspd"] = "keyword", + ["vcmptrue_usps"] = "keyword", + ["vcmptrue_ussd"] = "keyword", + ["vcmptrue_usss"] = "keyword", + ["vcmptruepd"] = "keyword", + ["vcmptrueps"] = "keyword", + ["vcmptruesd"] = "keyword", + ["vcmptruess"] = "keyword", + ["vcmpunord_qpd"] = "keyword", + ["vcmpunord_qps"] = "keyword", + ["vcmpunord_qsd"] = "keyword", + ["vcmpunord_qss"] = "keyword", + ["vcmpunord_spd"] = "keyword", + ["vcmpunord_sps"] = "keyword", + ["vcmpunord_ssd"] = "keyword", + ["vcmpunord_sss"] = "keyword", + ["vcmpunordpd"] = "keyword", + ["vcmpunordps"] = "keyword", + ["vcmpunordsd"] = "keyword", + ["vcmpunordss"] = "keyword", + ["vcomisd"] = "keyword", + ["vcomiss"] = "keyword", + ["vcompresspd"] = "keyword", + ["vcompressps"] = "keyword", + ["vcvtdq2pd"] = "keyword", + ["vcvtdq2ps"] = "keyword", + ["vcvtpd2dq"] = "keyword", + ["vcvtpd2ps"] = "keyword", + ["vcvtpd2qq"] = "keyword", + ["vcvtpd2udq"] = "keyword", + ["vcvtpd2uqq"] = "keyword", + ["vcvtph2ps"] = "keyword", + ["vcvtps2dq"] = "keyword", + ["vcvtps2pd"] = "keyword", + ["vcvtps2ph"] = "keyword", + ["vcvtps2qq"] = "keyword", + ["vcvtps2udq"] = "keyword", + ["vcvtps2uqq"] = "keyword", + ["vcvtqq2pd"] = "keyword", + ["vcvtqq2ps"] = "keyword", + ["vcvtsd2si"] = "keyword", + ["vcvtsd2ss"] = "keyword", + ["vcvtsd2usi"] = "keyword", + ["vcvtsi2sd"] = "keyword", + ["vcvtsi2ss"] = "keyword", + ["vcvtss2sd"] = "keyword", + ["vcvtss2si"] = "keyword", + ["vcvtss2usi"] = "keyword", + ["vcvttpd2dq"] = "keyword", + ["vcvttpd2qq"] = "keyword", + ["vcvttpd2udq"] = "keyword", + ["vcvttpd2uqq"] = "keyword", + ["vcvttps2dq"] = "keyword", + ["vcvttps2qq"] = "keyword", + ["vcvttps2udq"] = "keyword", + ["vcvttps2uqq"] = "keyword", + ["vcvttsd2si"] = "keyword", + ["vcvttsd2usi"] = "keyword", + ["vcvttss2si"] = "keyword", + ["vcvttss2usi"] = "keyword", + ["vcvtudq2pd"] = "keyword", + ["vcvtudq2ps"] = "keyword", + ["vcvtuqq2pd"] = "keyword", + ["vcvtuqq2ps"] = "keyword", + ["vcvtusi2sd"] = "keyword", + ["vcvtusi2ss"] = "keyword", + ["vdbpsadbw"] = "keyword", + ["vdivpd"] = "keyword", + ["vdivps"] = "keyword", + ["vdivsd"] = "keyword", + ["vdivss"] = "keyword", + ["vdppd"] = "keyword", + ["vdpps"] = "keyword", + ["verr"] = "keyword", + ["verw"] = "keyword", + ["vexp2pd"] = "keyword", + ["vexp2ps"] = "keyword", + ["vexpandpd"] = "keyword", + ["vexpandps"] = "keyword", + ["vextractf128"] = "keyword", + ["vextractf32x4"] = "keyword", + ["vextractf32x8"] = "keyword", + ["vextractf64x2"] = "keyword", + ["vextractf64x4"] = "keyword", + ["vextracti128"] = "keyword", + ["vextracti32x4"] = "keyword", + ["vextracti32x8"] = "keyword", + ["vextracti64x2"] = "keyword", + ["vextracti64x4"] = "keyword", + ["vextractps"] = "keyword", + ["vfixupimmpd"] = "keyword", + ["vfixupimmps"] = "keyword", + ["vfixupimmsd"] = "keyword", + ["vfixupimmss"] = "keyword", + ["vfmadd123pd"] = "keyword", + ["vfmadd123ps"] = "keyword", + ["vfmadd123sd"] = "keyword", + ["vfmadd123ss"] = "keyword", + ["vfmadd132pd"] = "keyword", + ["vfmadd132ps"] = "keyword", + ["vfmadd132sd"] = "keyword", + ["vfmadd132ss"] = "keyword", + ["vfmadd213pd"] = "keyword", + ["vfmadd213ps"] = "keyword", + ["vfmadd213sd"] = "keyword", + ["vfmadd213ss"] = "keyword", + ["vfmadd231pd"] = "keyword", + ["vfmadd231ps"] = "keyword", + ["vfmadd231sd"] = "keyword", + ["vfmadd231ss"] = "keyword", + ["vfmadd312pd"] = "keyword", + ["vfmadd312ps"] = "keyword", + ["vfmadd312sd"] = "keyword", + ["vfmadd312ss"] = "keyword", + ["vfmadd321pd"] = "keyword", + ["vfmadd321ps"] = "keyword", + ["vfmadd321sd"] = "keyword", + ["vfmadd321ss"] = "keyword", + ["vfmaddpd"] = "keyword", + ["vfmaddps"] = "keyword", + ["vfmaddsd"] = "keyword", + ["vfmaddss"] = "keyword", + ["vfmaddsub123pd"] = "keyword", + ["vfmaddsub123ps"] = "keyword", + ["vfmaddsub132pd"] = "keyword", + ["vfmaddsub132ps"] = "keyword", + ["vfmaddsub213pd"] = "keyword", + ["vfmaddsub213ps"] = "keyword", + ["vfmaddsub231pd"] = "keyword", + ["vfmaddsub231ps"] = "keyword", + ["vfmaddsub312pd"] = "keyword", + ["vfmaddsub312ps"] = "keyword", + ["vfmaddsub321pd"] = "keyword", + ["vfmaddsub321ps"] = "keyword", + ["vfmaddsubpd"] = "keyword", + ["vfmaddsubps"] = "keyword", + ["vfmsub123pd"] = "keyword", + ["vfmsub123ps"] = "keyword", + ["vfmsub123sd"] = "keyword", + ["vfmsub123ss"] = "keyword", + ["vfmsub132pd"] = "keyword", + ["vfmsub132ps"] = "keyword", + ["vfmsub132sd"] = "keyword", + ["vfmsub132ss"] = "keyword", + ["vfmsub213pd"] = "keyword", + ["vfmsub213ps"] = "keyword", + ["vfmsub213sd"] = "keyword", + ["vfmsub213ss"] = "keyword", + ["vfmsub231pd"] = "keyword", + ["vfmsub231ps"] = "keyword", + ["vfmsub231sd"] = "keyword", + ["vfmsub231ss"] = "keyword", + ["vfmsub312pd"] = "keyword", + ["vfmsub312ps"] = "keyword", + ["vfmsub312sd"] = "keyword", + ["vfmsub312ss"] = "keyword", + ["vfmsub321pd"] = "keyword", + ["vfmsub321ps"] = "keyword", + ["vfmsub321sd"] = "keyword", + ["vfmsub321ss"] = "keyword", + ["vfmsubadd123pd"] = "keyword", + ["vfmsubadd123ps"] = "keyword", + ["vfmsubadd132pd"] = "keyword", + ["vfmsubadd132ps"] = "keyword", + ["vfmsubadd213pd"] = "keyword", + ["vfmsubadd213ps"] = "keyword", + ["vfmsubadd231pd"] = "keyword", + ["vfmsubadd231ps"] = "keyword", + ["vfmsubadd312pd"] = "keyword", + ["vfmsubadd312ps"] = "keyword", + ["vfmsubadd321pd"] = "keyword", + ["vfmsubadd321ps"] = "keyword", + ["vfmsubaddpd"] = "keyword", + ["vfmsubaddps"] = "keyword", + ["vfmsubpd"] = "keyword", + ["vfmsubps"] = "keyword", + ["vfmsubsd"] = "keyword", + ["vfmsubss"] = "keyword", + ["vfnmadd123pd"] = "keyword", + ["vfnmadd123ps"] = "keyword", + ["vfnmadd123sd"] = "keyword", + ["vfnmadd123ss"] = "keyword", + ["vfnmadd132pd"] = "keyword", + ["vfnmadd132ps"] = "keyword", + ["vfnmadd132sd"] = "keyword", + ["vfnmadd132ss"] = "keyword", + ["vfnmadd213pd"] = "keyword", + ["vfnmadd213ps"] = "keyword", + ["vfnmadd213sd"] = "keyword", + ["vfnmadd213ss"] = "keyword", + ["vfnmadd231pd"] = "keyword", + ["vfnmadd231ps"] = "keyword", + ["vfnmadd231sd"] = "keyword", + ["vfnmadd231ss"] = "keyword", + ["vfnmadd312pd"] = "keyword", + ["vfnmadd312ps"] = "keyword", + ["vfnmadd312sd"] = "keyword", + ["vfnmadd312ss"] = "keyword", + ["vfnmadd321pd"] = "keyword", + ["vfnmadd321ps"] = "keyword", + ["vfnmadd321sd"] = "keyword", + ["vfnmadd321ss"] = "keyword", + ["vfnmaddpd"] = "keyword", + ["vfnmaddps"] = "keyword", + ["vfnmaddsd"] = "keyword", + ["vfnmaddss"] = "keyword", + ["vfnmsub123pd"] = "keyword", + ["vfnmsub123ps"] = "keyword", + ["vfnmsub123sd"] = "keyword", + ["vfnmsub123ss"] = "keyword", + ["vfnmsub132pd"] = "keyword", + ["vfnmsub132ps"] = "keyword", + ["vfnmsub132sd"] = "keyword", + ["vfnmsub132ss"] = "keyword", + ["vfnmsub213pd"] = "keyword", + ["vfnmsub213ps"] = "keyword", + ["vfnmsub213sd"] = "keyword", + ["vfnmsub213ss"] = "keyword", + ["vfnmsub231pd"] = "keyword", + ["vfnmsub231ps"] = "keyword", + ["vfnmsub231sd"] = "keyword", + ["vfnmsub231ss"] = "keyword", + ["vfnmsub312pd"] = "keyword", + ["vfnmsub312ps"] = "keyword", + ["vfnmsub312sd"] = "keyword", + ["vfnmsub312ss"] = "keyword", + ["vfnmsub321pd"] = "keyword", + ["vfnmsub321ps"] = "keyword", + ["vfnmsub321sd"] = "keyword", + ["vfnmsub321ss"] = "keyword", + ["vfnmsubpd"] = "keyword", + ["vfnmsubps"] = "keyword", + ["vfnmsubsd"] = "keyword", + ["vfnmsubss"] = "keyword", + ["vfpclasspd"] = "keyword", + ["vfpclassps"] = "keyword", + ["vfpclasssd"] = "keyword", + ["vfpclassss"] = "keyword", + ["vfrczpd"] = "keyword", + ["vfrczps"] = "keyword", + ["vfrczsd"] = "keyword", + ["vfrczss"] = "keyword", + ["vgatherdd"] = "keyword", + ["vgatherdpd"] = "keyword", + ["vgatherdps"] = "keyword", + ["vgatherdq"] = "keyword", + ["vgatherpf0dpd"] = "keyword", + ["vgatherpf0dps"] = "keyword", + ["vgatherpf0qpd"] = "keyword", + ["vgatherpf0qps"] = "keyword", + ["vgatherpf1dpd"] = "keyword", + ["vgatherpf1dps"] = "keyword", + ["vgatherpf1qpd"] = "keyword", + ["vgatherpf1qps"] = "keyword", + ["vgatherqd"] = "keyword", + ["vgatherqpd"] = "keyword", + ["vgatherqps"] = "keyword", + ["vgatherqq"] = "keyword", + ["vgetexppd"] = "keyword", + ["vgetexpps"] = "keyword", + ["vgetexpsd"] = "keyword", + ["vgetexpss"] = "keyword", + ["vgetmantpd"] = "keyword", + ["vgetmantps"] = "keyword", + ["vgetmantsd"] = "keyword", + ["vgetmantss"] = "keyword", + ["vhaddpd"] = "keyword", + ["vhaddps"] = "keyword", + ["vhsubpd"] = "keyword", + ["vhsubps"] = "keyword", + ["vinsertf128"] = "keyword", + ["vinsertf32x4"] = "keyword", + ["vinsertf32x8"] = "keyword", + ["vinsertf64x2"] = "keyword", + ["vinsertf64x4"] = "keyword", + ["vinserti128"] = "keyword", + ["vinserti32x4"] = "keyword", + ["vinserti32x8"] = "keyword", + ["vinserti64x2"] = "keyword", + ["vinserti64x4"] = "keyword", + ["vinsertps"] = "keyword", + ["vlddqu"] = "keyword", + ["vldmxcsr"] = "keyword", + ["vldqqu"] = "keyword", + ["vmaskmovd"] = "keyword", + ["vmaskmovdqu"] = "keyword", + ["vmaskmovpd"] = "keyword", + ["vmaskmovps"] = "keyword", + ["vmaskmovq"] = "keyword", + ["vmaxpd"] = "keyword", + ["vmaxps"] = "keyword", + ["vmaxsd"] = "keyword", + ["vmaxss"] = "keyword", + ["vmcall"] = "keyword", + ["vmclear"] = "keyword", + ["vmfunc"] = "keyword", + ["vminpd"] = "keyword", + ["vminps"] = "keyword", + ["vminsd"] = "keyword", + ["vminss"] = "keyword", + ["vmlaunch"] = "keyword", + ["vmload"] = "keyword", + ["vmmcall"] = "keyword", + ["vmovapd"] = "keyword", + ["vmovaps"] = "keyword", + ["vmovd"] = "keyword", + ["vmovddup"] = "keyword", + ["vmovdqa"] = "keyword", + ["vmovdqa32"] = "keyword", + ["vmovdqa64"] = "keyword", + ["vmovdqu"] = "keyword", + ["vmovdqu16"] = "keyword", + ["vmovdqu32"] = "keyword", + ["vmovdqu64"] = "keyword", + ["vmovdqu8"] = "keyword", + ["vmovhlps"] = "keyword", + ["vmovhpd"] = "keyword", + ["vmovhps"] = "keyword", + ["vmovlhps"] = "keyword", + ["vmovlpd"] = "keyword", + ["vmovlps"] = "keyword", + ["vmovmskpd"] = "keyword", + ["vmovmskps"] = "keyword", + ["vmovntdq"] = "keyword", + ["vmovntdqa"] = "keyword", + ["vmovntpd"] = "keyword", + ["vmovntps"] = "keyword", + ["vmovntqq"] = "keyword", + ["vmovq"] = "keyword", + ["vmovqqa"] = "keyword", + ["vmovqqu"] = "keyword", + ["vmovsd"] = "keyword", + ["vmovshdup"] = "keyword", + ["vmovsldup"] = "keyword", + ["vmovss"] = "keyword", + ["vmovupd"] = "keyword", + ["vmovups"] = "keyword", + ["vmpsadbw"] = "keyword", + ["vmptrld"] = "keyword", + ["vmptrst"] = "keyword", + ["vmread"] = "keyword", + ["vmresume"] = "keyword", + ["vmrun"] = "keyword", + ["vmsave"] = "keyword", + ["vmulpd"] = "keyword", + ["vmulps"] = "keyword", + ["vmulsd"] = "keyword", + ["vmulss"] = "keyword", + ["vmwrite"] = "keyword", + ["vmxoff"] = "keyword", + ["vmxon"] = "keyword", + ["vorpd"] = "keyword", + ["vorps"] = "keyword", + ["vpabsb"] = "keyword", + ["vpabsd"] = "keyword", + ["vpabsq"] = "keyword", + ["vpabsw"] = "keyword", + ["vpackssdw"] = "keyword", + ["vpacksswb"] = "keyword", + ["vpackusdw"] = "keyword", + ["vpackuswb"] = "keyword", + ["vpaddb"] = "keyword", + ["vpaddd"] = "keyword", + ["vpaddq"] = "keyword", + ["vpaddsb"] = "keyword", + ["vpaddsw"] = "keyword", + ["vpaddusb"] = "keyword", + ["vpaddusw"] = "keyword", + ["vpaddw"] = "keyword", + ["vpalignr"] = "keyword", + ["vpand"] = "keyword", + ["vpandd"] = "keyword", + ["vpandn"] = "keyword", + ["vpandnd"] = "keyword", + ["vpandnq"] = "keyword", + ["vpandq"] = "keyword", + ["vpavgb"] = "keyword", + ["vpavgw"] = "keyword", + ["vpblendd"] = "keyword", + ["vpblendmb"] = "keyword", + ["vpblendmd"] = "keyword", + ["vpblendmq"] = "keyword", + ["vpblendmw"] = "keyword", + ["vpblendvb"] = "keyword", + ["vpblendw"] = "keyword", + ["vpbroadcastb"] = "keyword", + ["vpbroadcastd"] = "keyword", + ["vpbroadcastmb2q"] = "keyword", + ["vpbroadcastmw2d"] = "keyword", + ["vpbroadcastq"] = "keyword", + ["vpbroadcastw"] = "keyword", + ["vpclmulhqhqdq"] = "keyword", + ["vpclmulhqlqdq"] = "keyword", + ["vpclmullqhqdq"] = "keyword", + ["vpclmullqlqdq"] = "keyword", + ["vpclmulqdq"] = "keyword", + ["vpcmov"] = "keyword", + ["vpcmpb"] = "keyword", + ["vpcmpd"] = "keyword", + ["vpcmpeqb"] = "keyword", + ["vpcmpeqd"] = "keyword", + ["vpcmpeqq"] = "keyword", + ["vpcmpeqw"] = "keyword", + ["vpcmpestri"] = "keyword", + ["vpcmpestrm"] = "keyword", + ["vpcmpgtb"] = "keyword", + ["vpcmpgtd"] = "keyword", + ["vpcmpgtq"] = "keyword", + ["vpcmpgtw"] = "keyword", + ["vpcmpistri"] = "keyword", + ["vpcmpistrm"] = "keyword", + ["vpcmpq"] = "keyword", + ["vpcmpub"] = "keyword", + ["vpcmpud"] = "keyword", + ["vpcmpuq"] = "keyword", + ["vpcmpuw"] = "keyword", + ["vpcmpw"] = "keyword", + ["vpcomb"] = "keyword", + ["vpcomd"] = "keyword", + ["vpcompressd"] = "keyword", + ["vpcompressq"] = "keyword", + ["vpcomq"] = "keyword", + ["vpcomub"] = "keyword", + ["vpcomud"] = "keyword", + ["vpcomuq"] = "keyword", + ["vpcomuw"] = "keyword", + ["vpcomw"] = "keyword", + ["vpconflictd"] = "keyword", + ["vpconflictq"] = "keyword", + ["vperm2f128"] = "keyword", + ["vperm2i128"] = "keyword", + ["vpermb"] = "keyword", + ["vpermd"] = "keyword", + ["vpermi2b"] = "keyword", + ["vpermi2d"] = "keyword", + ["vpermi2pd"] = "keyword", + ["vpermi2ps"] = "keyword", + ["vpermi2q"] = "keyword", + ["vpermi2w"] = "keyword", + ["vpermilpd"] = "keyword", + ["vpermilps"] = "keyword", + ["vpermpd"] = "keyword", + ["vpermps"] = "keyword", + ["vpermq"] = "keyword", + ["vpermt2b"] = "keyword", + ["vpermt2d"] = "keyword", + ["vpermt2pd"] = "keyword", + ["vpermt2ps"] = "keyword", + ["vpermt2q"] = "keyword", + ["vpermt2w"] = "keyword", + ["vpermw"] = "keyword", + ["vpexpandd"] = "keyword", + ["vpexpandq"] = "keyword", + ["vpextrb"] = "keyword", + ["vpextrd"] = "keyword", + ["vpextrq"] = "keyword", + ["vpextrw"] = "keyword", + ["vpgatherdd"] = "keyword", + ["vpgatherdq"] = "keyword", + ["vpgatherqd"] = "keyword", + ["vpgatherqq"] = "keyword", + ["vphaddbd"] = "keyword", + ["vphaddbq"] = "keyword", + ["vphaddbw"] = "keyword", + ["vphaddd"] = "keyword", + ["vphadddq"] = "keyword", + ["vphaddsw"] = "keyword", + ["vphaddubd"] = "keyword", + ["vphaddubq"] = "keyword", + ["vphaddubw"] = "keyword", + ["vphaddudq"] = "keyword", + ["vphadduwd"] = "keyword", + ["vphadduwq"] = "keyword", + ["vphaddw"] = "keyword", + ["vphaddwd"] = "keyword", + ["vphaddwq"] = "keyword", + ["vphminposuw"] = "keyword", + ["vphsubbw"] = "keyword", + ["vphsubd"] = "keyword", + ["vphsubdq"] = "keyword", + ["vphsubsw"] = "keyword", + ["vphsubw"] = "keyword", + ["vphsubwd"] = "keyword", + ["vpinsrb"] = "keyword", + ["vpinsrd"] = "keyword", + ["vpinsrq"] = "keyword", + ["vpinsrw"] = "keyword", + ["vplzcntd"] = "keyword", + ["vplzcntq"] = "keyword", + ["vpmacsdd"] = "keyword", + ["vpmacsdqh"] = "keyword", + ["vpmacsdql"] = "keyword", + ["vpmacssdd"] = "keyword", + ["vpmacssdqh"] = "keyword", + ["vpmacssdql"] = "keyword", + ["vpmacsswd"] = "keyword", + ["vpmacssww"] = "keyword", + ["vpmacswd"] = "keyword", + ["vpmacsww"] = "keyword", + ["vpmadcsswd"] = "keyword", + ["vpmadcswd"] = "keyword", + ["vpmadd52huq"] = "keyword", + ["vpmadd52luq"] = "keyword", + ["vpmaddubsw"] = "keyword", + ["vpmaddwd"] = "keyword", + ["vpmaskmovd"] = "keyword", + ["vpmaskmovq"] = "keyword", + ["vpmaxsb"] = "keyword", + ["vpmaxsd"] = "keyword", + ["vpmaxsq"] = "keyword", + ["vpmaxsw"] = "keyword", + ["vpmaxub"] = "keyword", + ["vpmaxud"] = "keyword", + ["vpmaxuq"] = "keyword", + ["vpmaxuw"] = "keyword", + ["vpminsb"] = "keyword", + ["vpminsd"] = "keyword", + ["vpminsq"] = "keyword", + ["vpminsw"] = "keyword", + ["vpminub"] = "keyword", + ["vpminud"] = "keyword", + ["vpminuq"] = "keyword", + ["vpminuw"] = "keyword", + ["vpmovb2m"] = "keyword", + ["vpmovd2m"] = "keyword", + ["vpmovdb"] = "keyword", + ["vpmovdw"] = "keyword", + ["vpmovm2b"] = "keyword", + ["vpmovm2d"] = "keyword", + ["vpmovm2q"] = "keyword", + ["vpmovm2w"] = "keyword", + ["vpmovmskb"] = "keyword", + ["vpmovq2m"] = "keyword", + ["vpmovqb"] = "keyword", + ["vpmovqd"] = "keyword", + ["vpmovqw"] = "keyword", + ["vpmovsdb"] = "keyword", + ["vpmovsdw"] = "keyword", + ["vpmovsqb"] = "keyword", + ["vpmovsqd"] = "keyword", + ["vpmovsqw"] = "keyword", + ["vpmovswb"] = "keyword", + ["vpmovsxbd"] = "keyword", + ["vpmovsxbq"] = "keyword", + ["vpmovsxbw"] = "keyword", + ["vpmovsxdq"] = "keyword", + ["vpmovsxwd"] = "keyword", + ["vpmovsxwq"] = "keyword", + ["vpmovusdb"] = "keyword", + ["vpmovusdw"] = "keyword", + ["vpmovusqb"] = "keyword", + ["vpmovusqd"] = "keyword", + ["vpmovusqw"] = "keyword", + ["vpmovuswb"] = "keyword", + ["vpmovw2m"] = "keyword", + ["vpmovwb"] = "keyword", + ["vpmovzxbd"] = "keyword", + ["vpmovzxbq"] = "keyword", + ["vpmovzxbw"] = "keyword", + ["vpmovzxdq"] = "keyword", + ["vpmovzxwd"] = "keyword", + ["vpmovzxwq"] = "keyword", + ["vpmuldq"] = "keyword", + ["vpmulhrsw"] = "keyword", + ["vpmulhuw"] = "keyword", + ["vpmulhw"] = "keyword", + ["vpmulld"] = "keyword", + ["vpmullq"] = "keyword", + ["vpmullw"] = "keyword", + ["vpmultishiftqb"] = "keyword", + ["vpmuludq"] = "keyword", + ["vpor"] = "keyword", + ["vpord"] = "keyword", + ["vporq"] = "keyword", + ["vpperm"] = "keyword", + ["vprold"] = "keyword", + ["vprolq"] = "keyword", + ["vprolvd"] = "keyword", + ["vprolvq"] = "keyword", + ["vprord"] = "keyword", + ["vprorq"] = "keyword", + ["vprorvd"] = "keyword", + ["vprorvq"] = "keyword", + ["vprotb"] = "keyword", + ["vprotd"] = "keyword", + ["vprotq"] = "keyword", + ["vprotw"] = "keyword", + ["vpsadbw"] = "keyword", + ["vpscatterdd"] = "keyword", + ["vpscatterdq"] = "keyword", + ["vpscatterqd"] = "keyword", + ["vpscatterqq"] = "keyword", + ["vpshab"] = "keyword", + ["vpshad"] = "keyword", + ["vpshaq"] = "keyword", + ["vpshaw"] = "keyword", + ["vpshlb"] = "keyword", + ["vpshld"] = "keyword", + ["vpshlq"] = "keyword", + ["vpshlw"] = "keyword", + ["vpshufb"] = "keyword", + ["vpshufd"] = "keyword", + ["vpshufhw"] = "keyword", + ["vpshuflw"] = "keyword", + ["vpsignb"] = "keyword", + ["vpsignd"] = "keyword", + ["vpsignw"] = "keyword", + ["vpslld"] = "keyword", + ["vpslldq"] = "keyword", + ["vpsllq"] = "keyword", + ["vpsllvd"] = "keyword", + ["vpsllvq"] = "keyword", + ["vpsllvw"] = "keyword", + ["vpsllw"] = "keyword", + ["vpsrad"] = "keyword", + ["vpsraq"] = "keyword", + ["vpsravd"] = "keyword", + ["vpsravq"] = "keyword", + ["vpsravw"] = "keyword", + ["vpsraw"] = "keyword", + ["vpsrld"] = "keyword", + ["vpsrldq"] = "keyword", + ["vpsrlq"] = "keyword", + ["vpsrlvd"] = "keyword", + ["vpsrlvq"] = "keyword", + ["vpsrlvw"] = "keyword", + ["vpsrlw"] = "keyword", + ["vpsubb"] = "keyword", + ["vpsubd"] = "keyword", + ["vpsubq"] = "keyword", + ["vpsubsb"] = "keyword", + ["vpsubsw"] = "keyword", + ["vpsubusb"] = "keyword", + ["vpsubusw"] = "keyword", + ["vpsubw"] = "keyword", + ["vpternlogd"] = "keyword", + ["vpternlogq"] = "keyword", + ["vptest"] = "keyword", + ["vptestmb"] = "keyword", + ["vptestmd"] = "keyword", + ["vptestmq"] = "keyword", + ["vptestmw"] = "keyword", + ["vptestnmb"] = "keyword", + ["vptestnmd"] = "keyword", + ["vptestnmq"] = "keyword", + ["vptestnmw"] = "keyword", + ["vpunpckhbw"] = "keyword", + ["vpunpckhdq"] = "keyword", + ["vpunpckhqdq"] = "keyword", + ["vpunpckhwd"] = "keyword", + ["vpunpcklbw"] = "keyword", + ["vpunpckldq"] = "keyword", + ["vpunpcklqdq"] = "keyword", + ["vpunpcklwd"] = "keyword", + ["vpxor"] = "keyword", + ["vpxord"] = "keyword", + ["vpxorq"] = "keyword", + ["vrangepd"] = "keyword", + ["vrangeps"] = "keyword", + ["vrangesd"] = "keyword", + ["vrangess"] = "keyword", + ["vrcp14pd"] = "keyword", + ["vrcp14ps"] = "keyword", + ["vrcp14sd"] = "keyword", + ["vrcp14ss"] = "keyword", + ["vrcp28pd"] = "keyword", + ["vrcp28ps"] = "keyword", + ["vrcp28sd"] = "keyword", + ["vrcp28ss"] = "keyword", + ["vrcpps"] = "keyword", + ["vrcpss"] = "keyword", + ["vreducepd"] = "keyword", + ["vreduceps"] = "keyword", + ["vreducesd"] = "keyword", + ["vreducess"] = "keyword", + ["vrndscalepd"] = "keyword", + ["vrndscaleps"] = "keyword", + ["vrndscalesd"] = "keyword", + ["vrndscaless"] = "keyword", + ["vroundpd"] = "keyword", + ["vroundps"] = "keyword", + ["vroundsd"] = "keyword", + ["vroundss"] = "keyword", + ["vrsqrt14pd"] = "keyword", + ["vrsqrt14ps"] = "keyword", + ["vrsqrt14sd"] = "keyword", + ["vrsqrt14ss"] = "keyword", + ["vrsqrt28pd"] = "keyword", + ["vrsqrt28ps"] = "keyword", + ["vrsqrt28sd"] = "keyword", + ["vrsqrt28ss"] = "keyword", + ["vrsqrtps"] = "keyword", + ["vrsqrtss"] = "keyword", + ["vscalefpd"] = "keyword", + ["vscalefps"] = "keyword", + ["vscalefsd"] = "keyword", + ["vscalefss"] = "keyword", + ["vscatterdpd"] = "keyword", + ["vscatterdps"] = "keyword", + ["vscatterpf0dpd"] = "keyword", + ["vscatterpf0dps"] = "keyword", + ["vscatterpf0qpd"] = "keyword", + ["vscatterpf0qps"] = "keyword", + ["vscatterpf1dpd"] = "keyword", + ["vscatterpf1dps"] = "keyword", + ["vscatterpf1qpd"] = "keyword", + ["vscatterpf1qps"] = "keyword", + ["vscatterqpd"] = "keyword", + ["vscatterqps"] = "keyword", + ["vshuff32x4"] = "keyword", + ["vshuff64x2"] = "keyword", + ["vshufi32x4"] = "keyword", + ["vshufi64x2"] = "keyword", + ["vshufpd"] = "keyword", + ["vshufps"] = "keyword", + ["vsqrtpd"] = "keyword", + ["vsqrtps"] = "keyword", + ["vsqrtsd"] = "keyword", + ["vsqrtss"] = "keyword", + ["vstmxcsr"] = "keyword", + ["vsubpd"] = "keyword", + ["vsubps"] = "keyword", + ["vsubsd"] = "keyword", + ["vsubss"] = "keyword", + ["vtestpd"] = "keyword", + ["vtestps"] = "keyword", + ["vucomisd"] = "keyword", + ["vucomiss"] = "keyword", + ["vunpckhpd"] = "keyword", + ["vunpckhps"] = "keyword", + ["vunpcklpd"] = "keyword", + ["vunpcklps"] = "keyword", + ["vxorpd"] = "keyword", + ["vxorps"] = "keyword", + ["vzeroall"] = "keyword", + ["vzeroupper"] = "keyword", + ["wait"] = "keyword", + ["wbinvd"] = "keyword", + ["wrfsbase"] = "keyword", + ["wrgsbase"] = "keyword", + ["wrmsr"] = "keyword", + ["wrpkru"] = "keyword", + ["wrshr"] = "keyword", + ["xabort"] = "keyword", + ["xadd"] = "keyword", + ["xbegin"] = "keyword", + ["xbts"] = "keyword", + ["xchg"] = "keyword", + ["xcryptcbc"] = "keyword", + ["xcryptcfb"] = "keyword", + ["xcryptctr"] = "keyword", + ["xcryptecb"] = "keyword", + ["xcryptofb"] = "keyword", + ["xend"] = "keyword", + ["xgetbv"] = "keyword", + ["xlat"] = "keyword", + ["xlatb"] = "keyword", + ["xor"] = "keyword", + ["xorpd"] = "keyword", + ["xorps"] = "keyword", + ["xrstor"] = "keyword", + ["xrstor64"] = "keyword", + ["xrstors"] = "keyword", + ["xrstors64"] = "keyword", + ["xsave"] = "keyword", + ["xsave64"] = "keyword", + ["xsavec"] = "keyword", + ["xsavec64"] = "keyword", + ["xsaveopt"] = "keyword", + ["xsaveopt64"] = "keyword", + ["xsaves"] = "keyword", + ["xsaves64"] = "keyword", + ["xsetbv"] = "keyword", + ["xsha1"] = "keyword", + ["xsha256"] = "keyword", + ["xstore"] = "keyword", + ["xtest"] = "keyword", + + -- Data + ["times"] = "keyword2", + ["equ"] = "keyword2", + ["db"] = "keyword2", + ["dw"] = "keyword2", + ["dd"] = "keyword2", + ["dq"] = "keyword2", + ["dt"] = "keyword2", + ["do"] = "keyword2", + ["dy"] = "keyword2", + ["dz"] = "keyword2", + ["resb"] = "keyword2", + ["resw"] = "keyword2", + ["resd"] = "keyword2", + ["resq"] = "keyword2", + ["rest"] = "keyword2", + ["reso"] = "keyword2", + ["resy"] = "keyword2", + ["resz"] = "keyword2", + ["incbin"] = "keyword2", + ["byte"] = "keyword2", + ["word"] = "keyword2", + ["dword"] = "keyword2", + ["qword"] = "keyword2", + ["short"] = "keyword2", + ["ptr"] = "keyword2", + ["tword"] = "keyword2", + ["yword"] = "keyword2", + ["zword"] = "keyword2", + ["oword"] = "keyword2", + + -- NASM directives + ["absolute"] = "keyword2", ["ABSOLUTE"] = "keyword2", + ["bits"] = "keyword2", ["BITS"] = "keyword2", + ["common"] = "keyword2", ["COMMON"] = "keyword2", + ["extern"] = "keyword2", ["EXTERN"] = "keyword2", + ["global"] = "keyword2", ["GLOBAL"] = "keyword2", + ["org"] = "keyword2", ["ORG"] = "keyword2", + ["section"] = "keyword2", ["SECTION"] = "keyword2", + ["seg"] = "keyword2", ["SEG"] = "keyword2", + ["segment"] = "keyword2", ["SEGMENT"] = "keyword2", + ["strict"] = "keyword2", ["STRICT"] = "keyword2", + ["use16"] = "keyword2", ["USE16"] = "keyword2", + ["use32"] = "keyword2", ["USE32"] = "keyword2", + ["use64"] = "keyword2", ["USE64"] = "keyword2", + ["..got"] = "keyword2", + ["..plt"] = "keyword2", + ["..sym"] = "keyword2", + ["wrt"] = "keyword2", + ["struc"] = "keyword2", + ["endstruc"] = "keyword2", + ["istruc"] = "keyword2", + ["at"] = "keyword2", ["AT"] = "keyword2", + ["iend"] = "keyword2", ["IEND"] = "keyword2", + ["align"] = "keyword2", ["ALIGN"] = "keyword2", + ["alignb"] = "keyword2", ["ALIGNB"] = "keyword2", + ["__SECT__"] = "keyword2", + ["__NASM_MAJOR__"] = "keyword2", + ["__NASM_MINOR__"] = "keyword2", + ["__NASM_SUBMINOR__"] = "keyword2", + ["___NASM_PATCHLEVEL__"] = "keyword2", + ["__NASM_VERSION_ID__"] = "keyword2", + ["__NASM_VER__"] = "keyword2", + ["__FILE__"] = "keyword2", + ["__LINE__"] = "keyword2", + ["__BITS__"] = "keyword2", + ["default"] = "keyword2", ["DEFAULT"] = "keyword2", + }, +} diff --git a/debian/extra/plugins/language_autohotkey_v1.lua b/debian/extra/plugins/language_autohotkey_v1.lua new file mode 100644 index 0000000..eb41ddc --- /dev/null +++ b/debian/extra/plugins/language_autohotkey_v1.lua @@ -0,0 +1,155 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +-- AHK has case insensitive grammer +local variables = { + "A_AhkPath", "A_AhkVersion", "A_AppData", "A_AppDataCommon", "A_AutoTrim", + "A_BatchLines", "A_CaretX", "A_CaretY", "A_Computername", "A_ControlDelay", + "A_Cursor", "A_DD", "A_DDD", "A_DDDD", "A_DefaultMouseSpeed", + "A_Desktop", "A_Desktopcommon", "A_Detecthiddentext", "A_Detecthiddenwindows", "A_Endchar", + "A_EventInfo", "A_ExitReason", "A_FileEncoding", "A_FormatFloat", "A_FormatInteger", + "A_Gui", "A_GuiControl", "A_GuiControlEvent", "A_GuiEvent", "A_GuiHeight", + "A_GuiWidth", "A_GuiX", "A_GuiY", "A_Hour", "A_IconFile", + "A_IconHidden", "A_IconNumber", "A_IconTip", "A_Index", "A_IpAddress1", + "A_IpAddress2", "A_IpAddress3", "A_IpAddress4", "A_Is64bitOS", "A_IsAdmin", + "A_IsCompiled", "A_IsCritical", "A_IsPaused", "A_IsSuspended", "A_IsUnicode", + "A_KeyDelay", "A_Language", "A_LastError", "A_LineFile", "A_LineNumber", + "A_LoopField", "A_LoopFileAttrib", "A_LoopFileDir", "A_LoopFileExt", "A_LoopFileFullPath", + "A_LoopFileLongPath", "A_LoopFileName", "A_LoopFileShortName", "A_LoopFileShortPath", "A_LoopFileSize", + "A_LoopFileSizeKB", "A_LoopFileSizeMB", "A_LoopFileTimeAccessed", "A_LoopFileTimeCreated", "A_LoopFileTimeModified", + "A_LoopReadLine", "A_LoopRegKey", "A_LoopRegName", "A_LoopRegSubKey", "A_LoopRegTimeModified", + "A_LoopRegType", "A_MDay", "A_Min", "A_MM", "A_MMM", + "A_MMMM", "A_Mon", "A_MouseDelay", "A_MSec", "A_MyDocuments", + "A_Now", "A_NowUTC", "A_NumBatchLines", "A_OSType", "A_OSVersion", + "A_PriorHotkey", "A_PriorKey", "A_ProgramFiles", "A_Programs", "A_ProgramsCommon", + "A_PtrSize", "A_RegView", "A_ScreenDpi", "A_ScreenHeight", "A_ScreenWidth", + "A_ScriptDir", "A_ScriptFullPath", "A_ScriptHwnd", "A_ScriptName", "A_Sec", + "A_Space", "A_StartMenu", "A_StartMenuCommon", "A_StartUp", "A_StartUpCommon", + "A_StringCaseSense", "A_Tab", "A_Temp", "A_ThisFunc", "A_ThisHotkey", + "A_ThisLabel", "A_ThisMenu", "A_ThisMenuItem", "A_ThisMenuItemPos", "A_TickCount", + "A_TimeIdle", "A_TimeIdlePhysical", "A_TimeSincePriorHotkey", "A_TimeSinceThisHotkey", "A_TitleMatchMode", + "A_TitleMatchModeSpeed", "A_UserName", "A_WDay", "A_WinDelay", "A_WinDir", + "A_WorkingDir", "A_YDay", "A_Year", "A_YWeek", "A_YYYY", + "CipboardAll", "Clipboard", "ComSpec", "ErrorLevel", "False", + "ProgramFiles", "True", +} + +local keywords = { + "Break", "ByRef", "Case", "Catch", "Class", + "Continue", "Else", "Else", "Exit", "ExitApp", + "Finally", "For", "Global", "Gosub", "Goto", + "If", "Local", "Loop", "OnExit", "Pause", + "Return", "Sleep", "static", "suspend", "Switch", + "Throw", "Try", "Until", "While", +} + +local functions = { + "_NewEnum", "Abs", "ACos", "Array", "Asc", + "ASin", "ATan", "Ceil", "Chr", "ComObjActive", + "ComObjArray", "ComObjConnect", "ComObjCreate", "ComObject", "ComObjError", + "ComObjFlags", "ComObjGet", "ComObjQuery", "ComObjType", "ComObjValue", + "Cos", "DllCall", "Exception", "Exp", "FileExist", + "FileOpen", "Floor", "Format", "Func", "GetKeyName", + "GetKeySC", "GetKeyState", "GetKeyVK", "IL_Add", "IL_Create", + "IL_Destroy", "InStr", "IsByRef", "IsFunc", "IsLabel", + "IsObject", "Ln", "Log", "LTrim", "LV_Add", + "LV_Delete", "LV_DeleteCol", "LV_GetCount", "LV_GetNext", "LV_GetText", + "LV_Insert", "LV_InsertCol", "LV_Modify", "LV_ModifyCol", "LV_SetImageList", + "Mod", "NumGet", "NumPut", "ObjAddRef", "ObjClone", + "Object", "ObjGetAddress", "ObjGetCapacity", "ObjHasKey", "ObjInsert", + "ObjMaxIndex", "ObjMinIndex", "ObjNewEnum", "ObjRelease", "ObjRemove", + "ObjSetCapacity", "OnMessage", "RegExMatch", "RegExReplace", "RegisterCallback", + "Round", "RTrim", "SB_SetIcon", "SB_SetParts", "SB_SetText", + "Sin", "Sqrt", "StrGet", "StrLen", "StrPut", + "StrReplace", "StrSplit", "SubStr", "Tan", "Trim", + "TV_Add", "TV_Delete", "TV_Get", "TV_GetChild", "TV_GetCount", + "TV_GetNext", "TV_GetParent", "TV_GetPrev", "TV_GetSelection", "TV_GetText", + "TV_Modify", "TV_SetImageList", "VarSetCapacity", "WinActive", "WinExist", +} + +local commands = { + "AutoTrim", "BlockInput", "Click", "ClipWait", "Control", + "ControlClick", "ControlFocus", "ControlGet", "ControlGetFocus", "ControlGetPos", + "ControlGetText", "ControlMove", "ControlSend", "ControlSendRaw", "ControlSetText", + "CoordMode", "Critical", "DetectHiddenText", "DetectHiddenWindows", "Drive", + "DriveGet", "DriveSpaceFree", "Edit", "EnvAdd", "EnvGet", + "EnvSet", "EnvSub", "EnvUpdate", "FileAppend", "FileCopy", + "FileCopyDir", "FileCreateDir", "FileCreateShortcut", "FileDelete", "FileEncoding", + "FileGetAttrib", "FileGetShortcut", "FileGetSize", "FileGetTime", "FileGetVersion", + "FileInstall", "FileMove", "FileMoveDir", "FileRead", "FileReadLine", + "FileRecycle", "FileRecycleEmpty", "FileRemoveDir", "FileSelectFile", "FileSelectFolder", + "FileSetAttrib", "FileSetTime", "FormatTime", "GroupActivate", "GroupAdd", + "GroupClose", "GroupDeactivate", "Gui", "GuiControl", "GuiControlGet", + "Hotkey", "ImageSearch", "IniDelete", "IniRead", "IniWrite", + "Input", "InputBox", "KeyHistory", "KeyWait", "ListHotkeys", + "ListLines", "ListVars", "Menu", "MouseClick", "MouseClickDrag", + "MouseGetPos", "MouseMove", "MsgBox", "OutputDebug", "PixelGetColor", + "PixelSearch", "PostMessage", "Process", "Random", "RegDelete", + "RegRead", "RegWrite", "Reload", "Run", "RunAs", + "RunWait", "Send", "SendEvent", "SendInput", "SendLevel", + "SendMessage", "SendMode", "SendPlay", "SendRaw", "SetBatchLines", + "SetCapsLockState", "SetControlDelay", "SetDefaultMouseSpeed", "SetEnv", "SetKeyDelay", + "SetMouseDelay", "SetNumLockState", "SetRegView", "SetScrollLockState", "SetStoreCapsLockMode", + "SetTimer", "SetTitleMatchMode", "SetWinDelay", "SetWorkingDir", "Shutdown", + "Sort", "SoundBeep", "SoundGet", "SoundGetWaveVolume", "SoundPlay", + "SoundSet", "SoundSetWaveVolume", "Splitpath", "StatusBarGetText", "StatusBarWait", + "StringCaseSense", "StringLower", "StringUpper", "SysGet", "Thread", + "ToolTip", "Transform", "TrayTip", "UrlDownloadToFile", "WinActivate", + "WinActivateBottom", "WinClose", "WinGet", "WinGetActiveStats", "WinGetActiveTitle", + "WinGetClass", "WinGetPos", "WinGetText", "WinGetTitle", "WinHide", + "WinKill", "WinMaximize", "WinMenuSelectItem", "WinMinimize", "WinMinimizeAll", + "WinMinimizeAllUndo", "WinMove", "WinRestore", "WinSet", "WinSetTitle", + "WinShow", "WinWait", "WinWaitActive", "WinWaitClose", "WinWaitNotActive", +} + +local symbols = {} +for _, elementVar in ipairs(variables) do + symbols[string.lower(elementVar)] = "operator" --a_year + symbols[string.upper(elementVar)] = "operator" --A_YEAR + symbols[string.format("%s%s", string.sub(elementVar, 1, 1), string.lower(string.sub(elementVar, 2)))] = "operator" --A_year + symbols[elementVar] = "operator" --A_Year +end + +for _, elementKeyword in ipairs(keywords) do + symbols[string.lower(elementKeyword)] = "function" --byref + symbols[string.upper(elementKeyword)] = "function" --BYREF + symbols[string.format("%s%s", string.sub(elementKeyword, 1, 1), string.lower(string.sub(elementKeyword, 2)))] = "function" --Byref + symbols[elementKeyword] = "function" --ByRef +end + +for _, elementFunction in ipairs(functions) do + symbols[string.lower(elementFunction)] = "keyword2" --lv_modifycol() + symbols[string.upper(elementFunction)] = "keyword2" --LV_MODIFYCOL() + symbols[string.format("%s%s", string.sub(elementFunction, 1, 1), string.lower(string.sub(elementFunction, 2)))] = "keyword2" --Lv_modifycol() + symbols[elementFunction] = "keyword2" --LV_ModifyCol() +end + +for _, elementCommands in ipairs(commands) do + symbols[string.lower(elementCommands)] = "keyword" --fileencoding + symbols[string.upper(elementCommands)] = "keyword" --FILEENCODING + symbols[string.format("%s%s", string.sub(elementCommands, 1, 1), string.lower(string.sub(elementCommands, 2)))] = "keyword" --Fileencoding + symbols[elementCommands] = "keyword" --FileEncoding +end + +syntax.add { + name = "AutoHotkey", + files = { "%.ahk$"}, + comment = ";", + patterns = { + { pattern = { ";", "\n" }, type = "comment" }, + { pattern = { "/%*", "*%/" }, type = "comment" }, + { pattern = { "[ruU]?%%", "[%% ]", '\\' }, type = "operator" }, + { pattern = { "[ruU]?%%", "[ ,]", '\\' }, type = "normal" }, + { pattern = { '[ruU]?"""', '"""'; '\\' }, type = "string" }, + { pattern = { '[ruU]?"', '"', '\\' }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "[%+%-=/%*%^<>!~|&]", type = "operator" }, + { pattern = ":=", type = "operator" }, + { pattern = ".=", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = symbols, +} diff --git a/debian/extra/plugins/language_awk.lua b/debian/extra/plugins/language_awk.lua new file mode 100644 index 0000000..cc56335 --- /dev/null +++ b/debian/extra/plugins/language_awk.lua @@ -0,0 +1,110 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Awk script", + files = "%.awk$", + headers = "^#!.*bin.*awk", + comment = "#", + patterns = { + -- $# is a awk special variable and the '#' shouldn't be interpreted + -- as a comment. + { pattern = "%$[%a_@*#][%w_]*", type = "keyword2" }, + -- Comments + { pattern = "#.*", type = "comment" }, + -- Strings + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { '`', '`', '\\' }, type = "string" }, + -- Ignore numbers that start with dots or slashes + { pattern = "%f[%w_%.%/]%d[%d%.]*%f[^%w_%.]", type = "number" }, + -- Operators + { pattern = "[!<>|&%[%]:=*]", type = "operator" }, + -- Match parameters + { pattern = "%f[%S][%+%-][%w%-_:]+", type = "function" }, + { pattern = "%f[%S][%+%-][%w%-_]+%f[=]", type = "function" }, + -- Prevent parameters with assignments from been matched as variables + { + pattern = "%s%-%a[%w_%-]*()%s+()%d[%d%.]+", + type = { "function", "normal", "number" } + }, + { + pattern = "%s%-%a[%w_%-]*()%s+()%a[%a%-_:=]+", + type = { "function", "normal", "symbol" } + }, + -- Match variable assignments + { pattern = "[_%a][%w_]+%f[%+=]", type = "keyword2" }, + -- Match variable expansions + { pattern = "%${.-}", type = "keyword2" }, + { pattern = "%$[%d%$%a_@*][%w_]*", type = "keyword2" }, + -- Functions + { pattern = "[%a_%-][%w_%-]*()%s*%f[(]", type = { "function", "normal" } }, + -- Everything else + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["break"] = "keyword", + ["continue"] = "keyword", + ["do"] = "keyword", + ["delete"] = "keyword", + ["else"] = "keyword", + ["exit"] = "keyword", + ["for"] = "keyword", + ["function"] = "keyword", + ["getline"] = "keyword", + ["if"] = "keyword", + ["next"] = "keyword", + ["nextfile"] = "keyword", + ["print"] = "keyword", + ["printf"] = "keyword", + ["return"] = "keyword", + ["while"] = "keyword", + ["gsub"] = "keyword", + ["index"] = "keyword", + ["length"] = "keyword", + ["match"] = "keyword", + ["split"] = "keyword", + ["sprintf"] = "keyword", + ["sub"] = "keyword", + ["substr"] = "keyword", + ["tolower"] = "keyword", + ["toupper"] = "keyword", + ["atan2"] = "keyword", + ["cos"] = "keyword", + ["exp"] = "keyword", + ["int"] = "keyword", + ["log"] = "keyword", + ["rand"] = "keyword", + ["sin"] = "keyword", + ["sqrt"] = "keyword", + ["srand"] = "keyword", + ["BEGIN"] = "keyword", + ["END"] = "keyword", + ["ARGC"] = "keyword", + ["ARGV"] = "keyword", + ["FILENAME"] = "keyword", + ["FNR"] = "keyword", + ["FS"] = "keyword", + ["NF"] = "keyword", + ["NR"] = "keyword", + ["OFMT"] = "keyword", + ["OFS"] = "keyword", + ["ORS"] = "keyword", + ["RLENGTH"] = "keyword", + ["RS"] = "keyword", + ["RSTART"] = "keyword", + ["SUBSEP"] = "keyword", + ["ARGIND"] = "keyword", + ["BINMODE"] = "keyword", + ["CONVFMT"] = "keyword", + ["ENVIRON"] = "keyword", + ["ERRNO"] = "keyword", + ["FIELDWIDTHS"] = "keyword", + ["IGNORECASE"] = "keyword", + ["LINT"] = "keyword", + ["PROCINFO"] = "keyword", + ["RT"] = "keyword", + ["RLENGTH"] = "keyword", + ["TEXTDOMAIN"] = "keyword" + } +} diff --git a/debian/extra/plugins/language_batch.lua b/debian/extra/plugins/language_batch.lua new file mode 100644 index 0000000..32510c8 --- /dev/null +++ b/debian/extra/plugins/language_batch.lua @@ -0,0 +1,63 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +-- batch syntax for lite + +-- windows batch files use caseless matching for symbols +local symtable = { + ["keyword"] = { + "if", "else", "not", "for", "do", "in", + "equ", "neq", "lss", "leq", "gtr", "geq", -- == != < <= > >= + "nul", "con", "prn", "prn", "lpt1", "com1", "com2", "com3", "com4", + "exist", "defined", + "errorlevel", "cmdextversion", + "goto", "call", "verify", + }, + ["function"] = { + "set", "setlocal", "endlocal", "enabledelayedexpansion", + "echo", "type", + "cd", "chdir", + "md", "mkdir", + "pause", "choice", "exit", + "del", "rd", "rmdir", + "copy", "xcopy", + "move", "ren", + "find", "findstr", + "sort", "shift", "attrib", + "cmd", "command", + "forfiles", + }, +} +-- prepare a mixed symbol list +local function prepare_symbols(symtable) + local symbols = { } + for symtype, symlist in pairs(symtable) do + for _, symname in ipairs(symlist) do + symbols[symname:lower()] = symtype + symbols[symname:upper()] = symtype + end + end + return symbols +end + +syntax.add { + name = "Batch", + files = { "%.bat$", "%.cmd$" }, + comment = "rem", + patterns = { + { pattern = "@echo off\n", type = "keyword" }, + { pattern = "@echo on\n", type = "keyword" }, + { pattern = "rem.-\n", type = "comment" }, -- rem comment line, rem, rem. + { pattern = "REM.-\n", type = "comment" }, + { pattern = "%s*:[%w%-]+", type = "symbol" }, -- :labels + { pattern = "%:%:.-\n", type = "comment" }, -- :: comment line + { pattern = "%%%w+%%", type = "symbol" }, -- %variable% + { pattern = "%%%%?~?[%w:]+", type = "symbol" }, -- %1, %~dpn1, %~1:2, %%i, %%~i + { pattern = "[!=()%>&%^/\\@]", type = "operator" }, -- operators + { pattern = "-?%.?%d+f?", type = "number" }, -- integer numbers + { pattern = { '"', '"', '\\' }, type = "string" }, -- "strings" + { pattern = "[%a_][%w_]*", type = "normal" }, + { pattern = ":eof", type = "keyword" }, -- not quite as intended, but ok for now + }, + symbols = prepare_symbols(symtable), +} diff --git a/debian/extra/plugins/language_bend.lua b/debian/extra/plugins/language_bend.lua new file mode 100644 index 0000000..5792084 --- /dev/null +++ b/debian/extra/plugins/language_bend.lua @@ -0,0 +1,65 @@ +-- Author: Rohan Vashisht https://github.com/RohanVashisht1234 + +-- mod-version:3 + +local syntax = require "core.syntax" + +syntax.add { + name = "Bend", + files = { "%.bend$" }, + comment = "#", + patterns = { + { pattern = "#.*", type = "comment" }, + { pattern = { '"', '"' }, type = "string" }, + { pattern = { "'", "'" }, type = "string" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "[%+%-=/%*%^%%<>!|&]", type = "operator" }, + { pattern = "def()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "data()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "let()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "Some()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "bend()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "object()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "fold()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "open()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "do()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "identity()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "lambda()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + }, + symbols = { + ["def"] = "keyword", + ["switch"] = "keyword", + ["case"] = "keyword", + ["return"] = "keyword", + ["if"] = "keyword", + ["else"] = "keyword", + ["when"] = "keyword", + ["match"] = "keyword", + ["λ"] = "keyword", + ["Some"] = "keyword", + ["data"] = "keyword", + ["let"] = "keyword", + ["use"] = "keyword", + ["object"] = "keyword", + ["fold"] = "keyword", + ["open"] = "keyword", + ["do"] = "keyword", + ["bind"] = "keyword", + ["Name"] = "keyword", + ["identity"] = "keyword", + ["Bool"] = "keyword", + ["ask"] = "keyword", + ["with"] = "keyword", + ["bend"] = "keyword2", + ["None"] = "keyword2", + ["Nil"] = "keyword2", + ["Result"] = "keyword2", + ["type"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + } +} diff --git a/debian/extra/plugins/language_bib.lua b/debian/extra/plugins/language_bib.lua new file mode 100644 index 0000000..1850ec6 --- /dev/null +++ b/debian/extra/plugins/language_bib.lua @@ -0,0 +1,23 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "BibTeX", + files = { "%.bib$" }, + comment = "%%", + patterns = { + { pattern = {"%%", "\n"}, type = "comment" }, + { pattern = "@%a+", type = "keyword" }, + { pattern = "%a+%s=", type = "keyword2" }, + }, + symbols = { + ["author"] = "keyword", + ["doi"] = "keyword", + ["issue"] = "keyword", + ["journal"] = "keyword", + ["month"] = "keyword", + ["numpages"] = "keyword", + ["pages"] = "keyword", + ["publisher"] = "keyword", + } +} diff --git a/debian/extra/plugins/language_blade.lua b/debian/extra/plugins/language_blade.lua new file mode 100644 index 0000000..0b82387 --- /dev/null +++ b/debian/extra/plugins/language_blade.lua @@ -0,0 +1,57 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Blade", + files = { "%.b$" }, + comment = "#", + patterns = { + { pattern = "#.*", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "%d+%.%d+", type = "number" }, + { pattern = "0x%x+", type = "number" }, + { pattern = "0c[0-8]+", type = "number" }, + { pattern = "0c[01]+", type = "number" }, + { pattern = "%d+", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "%a[%w_]+", type = "symbol" }, + }, + -- https://bladelang.com/tutorial/reserved.html#reserved-words + symbols = { + ["and"] = "keyword", + ["continue"] = "keyword", + ["else"] = "keyword", + ["in"] = "keyword", + ["self"] = "keyword2", + ["when"] = "keyword", + ["as"] = "keyword", + ["def"] = "keyword", + ["iter"] = "keyword", + ["static"] = "keyword", + ["while"] = "keyword", + ["assert"] = "keyword", + ["default"] = "keyword", + ["finally"] = "keyword", + ["break"] = "keyword", + ["die"] = "keyword", + ["for"] = "keyword", + ["or"] = "keyword", + ["try"] = "keyword", + ["catch"] = "keyword", + ["do"] = "keyword", + ["if"] = "keyword", + ["parent"] = "keyword", + ["using"] = "keyword", + ["class"] = "keyword", + ["echo"] = "function", + ["import"] = "keyword", + ["return"] = "keyword", + ["var"] = "keyword", + ["true"] = "literal", + ["false"] = "literal", + ["nil"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_blueprint.lua b/debian/extra/plugins/language_blueprint.lua new file mode 100644 index 0000000..98d6b06 --- /dev/null +++ b/debian/extra/plugins/language_blueprint.lua @@ -0,0 +1,90 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Blueprint", + files = { "%.blp$", }, + comment = "//", + block_comment = {"/*", "*/"}, + patterns = { + + -- Comments + { pattern = "//.*", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + + -- Strings + { pattern = { "'", "'", "\\"}, type = "string" }, + { pattern = { '"', '"', "\\" }, type = "string" }, + + -- Numbers + { pattern = "%.?%d+", type = "number" }, + + -- Child type + { pattern = "%[.*%]", type = "literal" }, + + -- Operators + { pattern = "%$", type = "operator" }, + { pattern = "=>%s*%$().*()%(%)", type = { "operator", "function", "normal" } }, + + -- Properties + { pattern = "[%w-_]+()%s*:", type = { "keyword", "normal" } }, + + -- Classes + { pattern = "[%w_-%.]+%s*(){", type = { "keyword2", "normal"} }, + { pattern = "[%w_-%.]+%s*()[%w_-]+%s*{", type = { "keyword2", "normal"} }, + + -- Symbols + { pattern = "[%w-_]+", type = "symbol" }, + + }, + symbols = { + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + + -- Import statements + ["using"] = "keyword", + + -- Keywords + ["after"] = "keyword", + ["bidirectional"] = "keyword", + ["bind-property"] = "keyword", + ["bind"] = "keyword", + ["default"] = "keyword", + ["destructive"] = "keyword", + ["disabled"] = "keyword", + ["inverted"] = "keyword", + ["no-sync-create"] = "keyword", + ["suggested"] = "keyword", + ["swapped"] = "keyword", + ["sync-create"] = "keyword", + ["template"] = "keyword", + + -- Menus + ["menu"] = "keyword", + ["submenu"] = "keyword", + ["section"] = "keyword", + + -- Nested blocks + ["responses"] = "keyword2", + ["items"] = "keyword2", + ["mime-types"] = "keyword2", + ["patterns"] = "keyword2", + ["suffixes"] = "keyword2", + ["marks"] = "keyword2", + ["widgets"] = "keyword2", + ["strings"] = "keyword2", + ["styles"] = "keyword2", + ["accessibility"] = "keyword2", + ["setters"] = "keyword2", + ["layout"] = "keyword2", + ["item"] = "keyword2", + ["condition"] = "keyword2", + ["mark"] = "keyword2", + + -- Translated strings + ["_"] = "operator", + ["C_"] = "operator", + } +} + diff --git a/debian/extra/plugins/language_brainfuck.lua b/debian/extra/plugins/language_brainfuck.lua new file mode 100644 index 0000000..31f2427 --- /dev/null +++ b/debian/extra/plugins/language_brainfuck.lua @@ -0,0 +1,23 @@ +-- Author: Rohan Vashisht: https://github.com/RohanVashisht1234/ + +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Brainfuck", -- tested ok + files = { + "%.bf$", -- tested ok + }, + patterns = { + { pattern = '%[', type = 'operator' }, -- tested ok + { pattern = '%]', type = 'operator' }, -- tested ok + { pattern = '%-', type = 'keyword' }, -- tested ok + { pattern = '<', type = 'keyword2' }, -- tested ok + { pattern = '>', type = 'keyword2' }, -- tested ok + { pattern = '+', type = 'string' }, -- tested ok + { pattern = ',', type = 'literal' }, -- tested ok + { pattern = '%.', type = 'string' }, -- tested ok + { pattern = '[^%-%.<>%+,%[%]]+', type = 'comment' }, -- tested ok + }, + symbols = {}, +} diff --git a/debian/extra/plugins/language_buzz.lua b/debian/extra/plugins/language_buzz.lua new file mode 100644 index 0000000..c00bf1a --- /dev/null +++ b/debian/extra/plugins/language_buzz.lua @@ -0,0 +1,76 @@ +-- Author: Rohan Vashisht: https://github.com/rohanvashisht1234/ + + +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Buzz", -- tested ok + files = { "%.buzz$" }, -- tested ok + comment = "|", -- tested ok + patterns = { + { pattern = { '"', '"', '\\' }, type = "string" }, -- tested ok + { pattern = "|.*", type = "comment" }, -- tested ok + { pattern = "[!%-/*?:=><]", type = "operator" }, -- tested ok + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- tested ok + { pattern = "const()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "object()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "var()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "-?%d+[%d%.eE_]*", type = "number" }, -- tested ok + { pattern = "-?%.?%d+", type = "number" }, -- tested ok + { pattern = "[%a_][%w_]*", type = "normal" }, -- tested ok + }, + symbols = { + ["bool"] = "keyword", -- tested ok + ["ud"] = "keyword", -- tested ok + ["float"] = "keyword", -- tested ok + ["zdef"] = "keyword", -- tested ok + ["resolve"] = "keyword", -- tested ok + ["yield"] = "keyword", -- tested ok + ["resume"] = "keyword", -- tested ok + ["export"] = "keyword", -- tested ok + ["void"] = "keyword", -- tested ok + ["protocol"] = "keyword", -- tested ok + ["do"] = "keyword", -- tested ok + ["enum"] = "keyword", -- tested ok + ["test"] = "keyword", -- tested ok + ["extern"] = "keyword", -- tested ok + ["object"] = "keyword", -- tested ok + ["foreach"] = "keyword", -- tested ok + ["is"] = "keyword", -- tested ok + ["return"] = "keyword", -- tested ok + ["continue"] = "keyword", -- tested ok + ["for"] = "keyword", -- tested ok + ["lambda"] = "keyword", -- tested ok + ["try"] = "keyword", -- tested ok + ["fun"] = "keyword", -- tested ok + ["type"] = "keyword", -- tested ok + ["while"] = "keyword", -- tested ok + ["and"] = "keyword", -- tested ok + ["global"] = "keyword", -- tested ok + ["not"] = "keyword2", -- tested ok + ["any"] = "keyword", -- tested ok + ["as"] = "keyword", -- tested ok + ["if"] = "keyword", -- tested ok + ["or"] = "keyword", -- tested ok + ["else"] = "keyword", -- tested ok + ["match"] = "keyword", -- tested ok + ["pat"] = "keyword", -- tested ok + ["import"] = "keyword", -- tested ok + ["str"] = "keyword", -- tested ok + ["var"] = "keyword", -- tested ok + ["catch"] = "keyword", -- tested ok + ["typeof"] = "keyword", -- tested ok + ["int"] = "keyword", -- tested ok + ["const"] = "keyword", -- tested ok + ["namespace"] = "keyword", -- tested ok + ["this"] = "keyword2", -- tested ok + ["null"] = "literal", -- tested ok + ["true"] = "literal", -- tested ok + ["false"] = "literal", -- tested ok + ["in"] = "literal", -- tested ok + ["static"] = "keyword2", -- tested ok + ["std"] = "keyword2", -- tested ok + ["io"] = "keyword2", -- tested ok + } +} diff --git a/debian/extra/plugins/language_c7.lua b/debian/extra/plugins/language_c7.lua new file mode 100644 index 0000000..2c3e2fc --- /dev/null +++ b/debian/extra/plugins/language_c7.lua @@ -0,0 +1,80 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "cel7", + files = "%.c7$", + comment = ";", + patterns = { + { pattern = ";.*", type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = "0x4000", type = "literal" }, + { pattern = "0x4040", type = "literal" }, + { pattern = "0x52a0", type = "literal" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "'", type = "symbol" }, + { pattern = "=", type = "symbol" }, + { pattern = "<=?", type = "symbol" }, + { pattern = "[%+-%*/]", type = "symbol" }, + { pattern = "//", type = "keyword2" }, + { pattern = "%%", type = "keyword2" }, + { pattern = "%f[^(][^()'%s\"]+", type = "function" }, + { pattern = "[^()'%s\"]+", type = "symbol" }, + }, + symbols = { + ["let"] = "keyword", + ["="] = "operator", + ["if"] = "keyword", + ["fn"] = "keyword", + ["mac"] = "keyword", + ["while"] = "keyword", + ["quote"] = "keyword", + ["'"] = "keyword", + ["and"] = "keyword", + ["or"] = "keyword", + ["do"] = "keyword", + ["cons"] = "keyword", + ["car"] = "keyword", + ["cdr"] = "keyword", + ["setcar"] = "keyword", + ["setcdr"] = "keyword", + ["list"] = "keyword", + ["not"] = "keyword", + ["is"] = "keyword", + ["atom"] = "keyword", + ["print"] = "keyword", + ["<"] = "operator", + ["<="] = "operator", + ["="] = "operator", + ["+"] = "operator", + ["-"] = "operator", + ["*"] = "operator", + ["/"] = "operator", + ["nil"] = "literal", + ["t"] = "literal", + + -- reserved variables (config) + ["title"] = "keyword2", + ["width"] = "keyword2", + ["height"] = "keyword2", + ["debug"] = "keyword2", + + -- callbacks + ["init"] = "keyword2", + ["step"] = "keyword2", + ["keydown"] = "keyword2", + ["keyup"] = "keyword2", + + -- built-in functions + ["quit"] = "keyword2", + ["rand"] = "keyword2", + ["poke"] = "keyword2", + ["peek"] = "keyword2", + ["color"] = "keyword2", + ["put"] = "keyword2", + ["get"] = "keyword2", + ["fill"] = "keyword2", + } +} diff --git a/debian/extra/plugins/language_caddyfile.lua b/debian/extra/plugins/language_caddyfile.lua new file mode 100644 index 0000000..d600aa0 --- /dev/null +++ b/debian/extra/plugins/language_caddyfile.lua @@ -0,0 +1,104 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + files = { PATHSEP .. "Caddyfile$" }, + comment = "#", + patterns = { + { pattern = "#.*", type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + -- Matcher definition + { pattern = "@[%w_]+", type = "operator" }, + -- Snippet + { pattern = "%(%g+%)", type = "operator" }, + -- Properties + { pattern = "^[%a_][%w_]*()%s+%f[%g]", + type = { "function", "normal" } + }, + { pattern = "^[%a_][%w_]*()%s+$", + type = { "function", "normal" } + }, + { pattern = "^%s*()[%a_][%w_]*()%s+$", + type = { "normal", "function", "normal" } + }, + { pattern = "^%s*()[%a_][%w_]*()%s+%f[%g]", + type = { "normal", "function", "normal" } + }, + -- Environment variables + { pattern = "{()%$[%w_]+():()[%w_]+()}", + type = { "operator", "keyword2", "operator", "keyword2", "operator" } + }, + { pattern = "{()%$[%w_]+()}", + type = { "operator", "keyword2", "operator" } + }, + -- Place holder + { pattern = "{%g-}", type = "keyword2" }, + -- Operators + { pattern = "[+%-,:]", type = "operator" }, + -- IP Address + { pattern = "%d+%.%d+%.%d+%.%d+", type = "literal" }, + -- Path /path/subpath + { pattern = "/[%w%./]+", type = "literal" }, + -- Wildcard domain *.levels + { pattern = "%*()[%w.]+", + type = { "operator", "literal" } + }, + -- Match Operator + { pattern = "%*+", type = "operator" }, + -- Domain leve1.level2 + { pattern = "https?://[%w%./%*]+", type = "literal" }, + -- Domain leve1.level2 + { pattern = "%w+%.[%w%.]+", type = "literal" }, + -- Number + { pattern = "%d+[mhskbi]*", type = "number" }, + -- Everything else for symbols to work + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["true"] = "literal", + ["false"] = "literal", + ["localhost"] = "literal", + + -- built-in directives + ["abort"] = "keyword", + ["acme_server"] = "keyword", + ["basicauth"] = "keyword", + ["bind"] = "keyword", + ["encode"] = "keyword", + ["error"] = "keyword", + ["file_server"] = "keyword", + ["forward_auth"] = "keyword", + ["handle"] = "keyword", + ["handle_errors"] = "keyword", + ["handle_path"] = "keyword", + ["header"] = "keyword", + ["import"] = "keyword", + ["log"] = "keyword", + ["method"] = "keyword", + ["map"] = "keyword", + ["metrics"] = "keyword", + ["php_fastcgi"] = "keyword", + ["push"] = "keyword", + ["redir"] = "keyword", + ["request_body"] = "keyword", + ["request_header"] = "keyword", + ["respond"] = "keyword", + ["reverse_proxy"] = "keyword", + ["rewrite"] = "keyword", + ["root"] = "keyword", + ["route"] = "keyword", + ["templates"] = "keyword", + ["tls"] = "keyword", + ["tracing"] = "keyword", + ["try_files"] = "keyword", + ["uri"] = "keyword", + ["vars"] = "keyword", + + -- Module directives + ["cgi"] = "keyword", + ["ssh"] = "keyword", + ["exec"] = "keyword", + ["supervisor"] = "keyword", + ["layer4"] = "keyword", + }, +} diff --git a/debian/extra/plugins/language_carbon.lua b/debian/extra/plugins/language_carbon.lua new file mode 100644 index 0000000..ea8c621 --- /dev/null +++ b/debian/extra/plugins/language_carbon.lua @@ -0,0 +1,83 @@ +-- Author: Rohan Vashisht: https://github.com/rohanvashisht1234/ + +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Carbon", -- tested ok + files = { + "%.carbon$" -- tested ok + }, + comment = "//", -- tested ok + patterns = { + { pattern = { '"', '"', '\\' }, type = "string" }, -- tested ok + { pattern = { '"""', '"""', '\\' }, type = "string" }, -- tested ok + { pattern = { "'''", "'''", '\\' }, type = "string" }, -- tested ok + { pattern = "//.*", type = "comment" }, -- tested ok + { pattern = "[!%-/*?:=><+]", type = "operator" }, -- tested ok + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- tested ok + { pattern = "packages()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "let()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "import()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "impl()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "class()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "var()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "package()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "-?%d+[%d%.eE_]*", type = "number" }, -- tested ok + { pattern = "-?%.?%d+", type = "number" }, -- tested ok + { pattern = "[%a_][%w_]*", type = "normal" }, -- tested ok + }, + symbols = { + ["package"] = "keyword", -- tested ok + ["import"] = "keyword", -- tested ok + ["fn"] = "keyword", -- tested ok + ["var"] = "keyword", -- tested ok + ["for"] = "keyword", -- tested ok + ["return"] = "keyword", -- tested ok + ["class"] = "keyword", -- tested ok + ["api"] = "keyword", -- tested ok + ["i8"] = "keyword", -- tested ok + ["i16"] = "keyword", -- tested ok + ["i32"] = "keyword", -- tested ok + ["i64"] = "keyword", -- tested ok + ["i128"] = "keyword", -- tested ok + ["i256"] = "keyword", -- tested ok + ["u8"] = "keyword", -- tested ok + ["u16"] = "keyword", -- tested ok + ["u32"] = "keyword", -- tested ok + ["u64"] = "keyword", -- tested ok + ["u128"] = "keyword", -- tested ok + ["u256"] = "keyword", -- tested ok + ["f8"] = "keyword", -- tested ok + ["f16"] = "keyword", -- tested ok + ["f32"] = "keyword", -- tested ok + ["f64"] = "keyword", -- tested ok + ["f128"] = "keyword", -- tested ok + ["if"] = "keyword", -- tested ok + ["else"] = "keyword", -- tested ok + ["auto"] = "keyword", -- tested ok + ["let"] = "keyword", -- tested ok + ["File"] = "keyword", -- tested ok + ["while"] = "keyword", -- tested ok + ["match"] = "keyword", -- tested ok + ["case"] = "keyword", -- tested ok + ["default"] = "keyword", -- tested ok + ["returned"] = "keyword", -- tested ok + ["base"] = "keyword", -- tested ok + ["bool"] = "keyword", -- tested ok + ["virtual"] = "keyword", -- tested ok + ["abstract"] = "keyword", -- tested ok + ["String"] = "keyword", -- tested ok + + ["impl"] = "keyword2", -- tested ok + ["extend"] = "keyword", -- tested ok + ["partial"] = "keyword2", -- tested ok + ["Self"] = "keyword", -- tested ok + ["Int"] = "keyword", -- tested ok + ["UInt"] = "keyword", -- tested ok + ["Base"] = "keyword", -- tested ok + ["template"] = "keyword2", -- tested ok + ["true"] = "keyword2", -- tested ok + ["false"] = "keyword2", -- tested ok + } +} diff --git a/debian/extra/plugins/language_clojure.lua b/debian/extra/plugins/language_clojure.lua new file mode 100644 index 0000000..1344718 --- /dev/null +++ b/debian/extra/plugins/language_clojure.lua @@ -0,0 +1,56 @@ +-- Author: Rohan Vashisht: https://github.com/RohanVashisht1234/ + +-- mod-version:3 +local syntax = require "core.syntax" +syntax.add { + name = "Clojure", + comment = ";;", + files = { + "%.clj$", + "%.cljs$", + "%.clc$", + "%.edn$", + }, + patterns = { + { pattern = ';;.*', type = 'comment' }, -- Single-line Comment + { pattern = ';.*', type = 'comment' }, -- Single-line Comment + { pattern = { '#"', '"', '\\' }, type = 'string' }, -- Multiline String + { pattern = { '"', '"', '\\' }, type = 'string' }, -- Multiline String + { pattern = { '"""', '"""', '\\' }, type = 'string' }, -- Multiline String + { pattern = ':[%a_][%w_/%-]*', type = 'keyword2' }, -- word after ':' a.k.a (Var metadata) + { pattern = '[%a_][%w_]*()%.()[%a_][%w_/%-]*', type = { 'keyword', 'operator', 'keyword2' } }, -- Things like something.something + { pattern = "%(()def()%s+()[%a_][%w_%-]*", type = { "normal", "keyword", "literal", 'literal' } }, -- function definition + { pattern = "%(()def[%a_][%w_]*()%s+()[%a_][%w_%-]*", type = { "normal", "keyword", "literal", 'literal' } }, -- function definition but with something along with def like: defn, defmacro etc. + { pattern = '%(()require()%s+()[%a_][%w_]*', type = { 'normal', 'keyword', 'literal', 'literal' } }, -- highlight the word after require keyword + { pattern = '%(()[%a_][%w_/]*', type = { 'normal', 'literal' } }, -- patterns that are like this: (my_function/subdir_1) + { pattern = '-?0x%x+', type = 'number' }, -- Hexadecimal + { pattern = '-?%d+[%d%.eE]*f?', type = 'number' }, -- Floating-point numbers + { pattern = '-?%.?%d+f?', type = 'number' }, -- Floating-point numbers + { pattern = '[!%#%$%%&*+./%<=>%?@\\%^|%-~:]', type = 'operator' }, -- Character classes + { pattern = "[%a_'][%w_']*", type = 'normal' }, -- Normal + }, + symbols = { + ['def'] = 'keyword', -- tested ok + ['defn'] = 'keyword', -- tested ok + ['str'] = 'keyword', -- tested ok + ['fn'] = 'keyword', -- tested ok + ['println'] = 'keyword', -- tested ok + ['if'] = 'keyword', -- tested ok + ['cond'] = 'keyword', -- tested ok + ['vector'] = 'keyword', -- tested ok + ['apply'] = 'keyword', -- tested ok + ['String'] = 'keyword', -- tested ok + ['ns'] = 'keyword', -- tested ok + ['try'] = 'keyword', -- tested ok + ['let'] = 'keyword', -- tested ok + ['get'] = 'keyword', -- tested ok + ['catch'] = 'keyword', -- tested ok + ['Retention'] = 'keyword', -- tested ok + ['Deprecated'] = 'keyword', -- tested ok + ['require'] = 'keyword2', -- tested ok + ['true'] = 'keyword2', -- tested ok + ['false'] = 'keyword2', -- tested ok + ['nil'] = 'literal', -- tested ok + ['int'] = 'literal', -- tested ok + }, +} diff --git a/debian/extra/plugins/language_cmake.lua b/debian/extra/plugins/language_cmake.lua new file mode 100644 index 0000000..05c45a3 --- /dev/null +++ b/debian/extra/plugins/language_cmake.lua @@ -0,0 +1,19 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "CMake", + files = { "%.cmake$", PATHSEP .. "CMakeLists%.txt$" }, + comment = "#", + block_comment = { "#[[", "]]" }, + patterns = { + { pattern = { '#%[=*%[', '%]=*%]' }, type = "comment" }, + { pattern = "#.*", type = "comment" }, + { pattern = { '%[=*%[', '%]=*%]' }, type = "string" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "normal" }, + { pattern = "%${[%a_][%w_]*%}", type = "operator" }, + }, + symbols = {}, +} diff --git a/debian/extra/plugins/language_csharp.lua b/debian/extra/plugins/language_csharp.lua new file mode 100644 index 0000000..c137b63 --- /dev/null +++ b/debian/extra/plugins/language_csharp.lua @@ -0,0 +1,122 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "C#", + files = "%.cs$", + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "[%$%@]?\"", '"', '\\' }, type = "string" }, -- string interpolation and verbatim + { pattern = "'\\x%x?%x?%x?%x'", type = "string" }, -- character hexadecimal escape sequence + { pattern = "'\\u%x%x%x%x'", type = "string" }, -- character unicode escape sequence + { pattern = "'\\?.'", type = "string" }, -- character literal + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "%?%?", type = "operator" }, -- ?? null-coalescing + { pattern = "%?%.", type = "operator" }, -- ?. null-conditional + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + -- keywords and contextual keywords + ["abstract"] = "keyword", + ["as"] = "keyword", + ["add"] = "keyword", + ["await"] = "keyword", + ["base"] = "keyword", + ["break"] = "keyword", + ["case"] = "keyword", + ["catch"] = "keyword", + ["checked"] = "keyword", + ["class"] = "keyword", + ["record"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["default"] = "keyword", + ["delegate"] = "keyword", + ["do"] = "keyword", + ["else"] = "keyword", + ["enum"] = "keyword", + ["event"] = "keyword", + ["explicit"] = "keyword", + ["extern"] = "keyword", + ["finally"] = "keyword", + ["fixed"] = "keyword", + ["for"] = "keyword", + ["foreach"] = "keyword", + ["get"] = "keyword", + ["goto"] = "keyword", + ["if"] = "keyword", + ["implicit"] = "keyword", + ["in"] = "keyword", + ["interface"] = "keyword", + ["internal"] = "keyword", + ["is"] = "keyword", + ["lock"] = "keyword", + ["namespace"] = "keyword", + ["new"] = "keyword", + ["operator"] = "keyword", + ["out"] = "keyword", + ["override"] = "keyword", + ["remove"] = "keyword", + ["params"] = "keyword", + ["partial"] = "keyword", + ["private"] = "keyword", + ["protected"] = "keyword", + ["dynamic"] = "keyword", + ["public"] = "keyword", + ["readonly"] = "keyword", + ["ref"] = "keyword", + ["return"] = "keyword", + ["sealed"] = "keyword", + ["set"] = "keyword", + ["sizeof"] = "keyword", + ["stackalloc"] = "keyword", + ["static"] = "keyword", + ["struct"] = "keyword", + ["switch"] = "keyword", + ["this"] = "keyword", + ["throw"] = "keyword", + ["try"] = "keyword", + ["typeof"] = "keyword", + ["unchecked"] = "keyword", + ["unsafe"] = "keyword", + ["using"] = "keyword", + ["var"] = "keyword", + ["value"] = "keyword", + ["global"] = "keyword", + ["virtual"] = "keyword", + ["void"] = "keyword", + ["volatile"] = "keyword", + ["where"] = "keyword", + ["when"] = "keyword", + ["while"] = "keyword", + ["yield"] = "keyword", + -- types + ["bool"] = "keyword2", + ["byte"] = "keyword2", + ["char"] = "keyword2", + ["decimal"] = "keyword2", + ["double"] = "keyword2", + ["float"] = "keyword2", + ["int"] = "keyword2", + ["long"] = "keyword2", + ["object"] = "keyword2", + ["sbyte"] = "keyword2", + ["short"] = "keyword2", + ["string"] = "keyword2", + ["uint"] = "keyword2", + ["ulong"] = "keyword2", + ["ushort"] = "keyword2", + -- literals + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + }, +} + diff --git a/debian/extra/plugins/language_cue.lua b/debian/extra/plugins/language_cue.lua new file mode 100644 index 0000000..50f01f3 --- /dev/null +++ b/debian/extra/plugins/language_cue.lua @@ -0,0 +1,41 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "CUE", + files = "%.cue$", + comment = "//", + patterns = { + { pattern = "//.*", type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "`", "`", '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "0[oO_][0-7]+i?", type = "number" }, + { pattern = "-?0x[%x_]+i?", type = "number" }, + { pattern = "-?%d+_%di?", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?i?", type = "number" }, + { pattern = "-?%.?%d+f?i?", type = "number" }, + { pattern = "[%a_][%w_]*%.", type = "literal" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "#[%a][%w_]*", type = "keyword2" }, + -- operators + { pattern = "[%+%-=/%*%^%%<>!~|&%?:%.]", type = "operator" }, + }, + symbols = { + ["package"] = "keyword", + ["import"] = "keyword", + ["let"] = "keyword", + ["for"] = "keyword", + ["true"] = "literal", + ["false"] = "literal", + ["string"] = "keyword2", + ["bool"] = "keyword2", + ["number"] = "keyword2", + ["uint32"] = "keyword2", + ["int32"] = "keyword2", + ["uint16"] = "keyword2", + ["int16"] = "keyword2", + ["uint8"] = "keyword2", + ["float"] = "keyword2", + } +} diff --git a/debian/extra/plugins/language_d.lua b/debian/extra/plugins/language_d.lua new file mode 100644 index 0000000..282c026 --- /dev/null +++ b/debian/extra/plugins/language_d.lua @@ -0,0 +1,135 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "D", + files = { "%.d$", "%.di$" }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { "/%+", "%+/" }, type = "comment" }, + { pattern = { '`', '`', '\\' }, type = "string" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?0x[%x_]+", type = "number" }, + { pattern = "-?[%d_]+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&%$]+", type = "operator" }, + { pattern = "[%a_][%w_]*!?()[%(.]", type = {"function", "normal"} }, -- highlight templates + { pattern = "@safe", type = "keyword" }, + { pattern = "@trusted", type = "keyword" }, + { pattern = "@nogc", type = "keyword" }, + }, + symbols = { + ["abstract"] = "keyword", + ["alias"] = "keyword", + ["align"] = "keyword", + ["asm"] = "keyword", + ["assert"] = "keyword", + ["auto"] = "keyword", + ["body"] = "keyword", + ["bool"] = "keyword2", + ["break"] = "keyword", + ["byte"] = "keyword2", + ["case"] = "keyword", + ["cast"] = "keyword", + ["catch"] = "keyword", + ["cdouble"] = "keyword2", + ["cent"] = "keyword2", + ["cfloat"] = "keyword2", + ["char"] = "keyword2", + ["class"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["creal"] = "keyword2", + ["dchar"] = "keyword2", + ["debug"] = "keyword", + ["default"] = "keyword", + ["delegate"] = "keyword", + ["deprecated"] = "keyword", + ["do"] = "keyword", + ["double"] = "keyword2", + ["else"] = "keyword", + ["enum"] = "keyword", + ["export"] = "keyword", + ["extern"] = "keyword", + ["false"] = "literal", + ["final"] = "keyword", + ["finally"] = "keyword", + ["float"] = "keyword2", + ["for"] = "keyword", + ["foreach"] = "keyword", + ["foreach_reverse"] = "keyword", + ["function"] = "keyword", + ["goto"] = "keyword", + ["idouble"] = "keyword2", + ["if"] = "keyword", + ["ifloat"] = "keyword2", + ["immutable"] = "keyword", + ["import"] = "keyword", + ["in"] = "keyword", + ["inout"] = "keyword", + ["int"] = "keyword2", + ["interface"] = "keyword", + ["invariant"] = "keyword", + ["ireal"] = "keyword2", + ["is"] = "keyword", + ["lazy"] = "keyword", + ["long"] = "keyword2", + ["macro"] = "keyword", + ["mixin"] = "keyword", + ["module"] = "keyword", + ["new"] = "keyword", + ["nothrow"] = "keyword", + ["null"] = "literal", + ["out"] = "keyword", + ["override"] = "keyword", + ["package"] = "keyword", + ["pragma"] = "keyword", + ["private"] = "keyword", + ["protected"] = "keyword", + ["public"] = "keyword", + ["pure"] = "keyword", + ["real"] = "keyword2", + ["ref"] = "keyword", + ["return"] = "keyword", + ["scope"] = "keyword", + ["shared"] = "keyword", + ["short"] = "keyword2", + ["static"] = "keyword", + ["struct"] = "keyword", + ["super"] = "keyword", + ["switch"] = "keyword", + ["synchronized"] = "keyword", + ["template"] = "keyword", + ["this"] = "keyword", + ["throw"] = "keyword", + ["true"] = "literal", + ["try"] = "keyword", + ["typeid"] = "keyword", + ["typeof"] = "keyword", + ["ubyte"] = "keyword2", + ["ucent"] = "keyword2", + ["uint"] = "keyword2", + ["ulong"] = "keyword2", + ["union"] = "keyword", + ["unittest"] = "keyword", + ["ushort"] = "keyword2", + ["version"] = "keyword", + ["void"] = "keyword", + ["wchar"] = "keyword2", + ["while"] = "keyword", + ["with"] = "keyword", + ["__FILE__"] = "keyword", + ["__FILE_FULL_PATH__"] = "keyword", + ["__MODULE__"] = "keyword", + ["__LINE__"] = "keyword", + ["__FUNCTION__"] = "keyword", + ["__PRETTY_FUNCTION__"] = "keyword", + ["__gshared"] = "keyword", + ["__traits"] = "keyword", + ["__vector"] = "keyword", + ["__parameters"] = "keyword", + }, +} diff --git a/debian/extra/plugins/language_dart.lua b/debian/extra/plugins/language_dart.lua new file mode 100644 index 0000000..03274b2 --- /dev/null +++ b/debian/extra/plugins/language_dart.lua @@ -0,0 +1,64 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Dart", + files = { "%.dart$" }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = "///.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "%?%?", type = "operator" }, + { pattern = "%?%.", type = "operator" }, + { pattern = { "[%$%@]?\"", '"', '\\' }, type = "string" }, + { pattern = "'\\x%x?%x?%x?%x'", type = "string" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["await"] = "keyword", + ["bool"] = "keyword2", + ["break"] = "keyword", + ["case"] = "keyword", + ["class"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["default"] = "keyword", + ["do"] = "keyword", + ["double"] = "keyword2", + ["dynamic"] = "keyword2", + ["else"] = "keyword", + ["enum"] = "keyword", + ["false"] = "literal", + ["final"] = "keyword", + ["finally"] = "keyword", + ["for"] = "keyword", + ["Function"] = "keyword2", + ["if"] = "keyword", + ["in"] = "keyword", + ["int"] = "keyword2", + ["List"] = "keyword2", + ["Map"] = "keyword2", + ["new"] = "keyword", + ["null"] = "literal", + ["part of"] = "keyword", + ["print"] = "keyword", + ["return"] = "keyword", + ["static"] = "keyword", + ["String"] = "keyword2", + ["switch"] = "keyword", + ["then"] = "keyword", + ["this"] = "keyword2", + ["true"] = "literal", + ["void"] = "keyword", + ["while"] = "keyword", + }, +} + diff --git a/debian/extra/plugins/language_diff.lua b/debian/extra/plugins/language_diff.lua new file mode 100644 index 0000000..c4c5a90 --- /dev/null +++ b/debian/extra/plugins/language_diff.lua @@ -0,0 +1,70 @@ +-- mod-version:3 +local syntax = require "core.syntax" +local style = require "core.style" +local common = require "core.common" + +-- we need these symbol types to have uniform colors +style.syntax["diff_add"] = { common.color "#72b886" } +style.syntax["diff_del"] = { common.color "#F36161" } + +syntax.add { + name = "Diff", + files = { "%.diff$", "%.patch$", "%.rej$" }, + headers = "^diff %-", + patterns = { + -- Method the patch was generated with and source/target files + { regex = "^diff .+", type = "function" }, + -- Seen for changing the file permissions + { regex = "^new .+", type = "comment" }, + -- Usually holds starting and ending commit + { regex = "^index .+", type = "comment" }, + -- Position to patch + { + pattern = "@@.-@@ ().+", --with heading + type = { "number", "string" } + }, + { + regex = "^@@ [\\d,\\-\\+ ]+ @@\n", --wihtout heading + type = "number" + }, + -- Other position to patch formats + { + regex = "^-{3} [\\d]+,[\\d]+ \\-{4}\n", + type = "number" + }, + { + regex = "^\\*{3} [\\d]+,[\\d]+ \\*{4}\n", + type = "number" + }, + -- Source and target file + { regex = "^-{3} .+", type = "keyword" }, + { regex = "^\\+{3} .+", type = "keyword" }, + -- Rarely used source file indicator + { regex = "^\\*{3} .+", type = "keyword" }, + -- git patches seem to add 3 dashes to separate message from changed files + { regex = "^-{3}\n", type = "normal" }, + -- Addition and deletion of lines + { regex = "^-.*", type = "diff_del" }, + { regex = "^\\+.*", type = "diff_add" }, + { regex = "^<.*", type = "diff_del" }, + { regex = "^>.*", type = "diff_add" }, + -- Change between two lines + { regex = "^!.*", type = "number" }, + -- Stuff usually found on a authored patch heading + { + pattern = "From ()[a-fA-F0-9]+ ().+", + type = { "keyword", "number", "string" } + }, + { regex = "^[a-zA-Z\\-]+: ", type = "keyword" }, + -- Diff stats + { regex = "^ [\\d]+ files? changed", type = "function" }, + { regex = "[\\d]+ insertions?\\(\\+\\)", type = "diff_add" }, + { regex = "[\\d]+ deletions?\\(\\-\\)", type = "diff_del" }, + -- Match e-mail + { + pattern = ".*()<[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+%.[a-zA-Z0-9-.]+>", + type = {"string", "keyword2"} + }, + }, + symbols = {} +} diff --git a/debian/extra/plugins/language_edp.lua b/debian/extra/plugins/language_edp.lua new file mode 100644 index 0000000..0454288 --- /dev/null +++ b/debian/extra/plugins/language_edp.lua @@ -0,0 +1,645 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "FreeFEM++", + files = { + "%.edp$", "%.ffp$" + }, + comment = "//", + block_comment = { "/*", "*/" }, + patterns = { + { pattern = "//.*", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = "0x%x+[%x']*", type = "number" }, + { pattern = "%d+[%d%.'eE]*f?", type = "number" }, + { pattern = "%.?%d+[%d']*f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|:&]", type = "operator" }, + { pattern = "##", type = "operator" }, + { pattern = "struct%s()[%a_][%w_]*", type = { "keyword", "keyword2" } }, + { pattern = "class%s()[%a_][%w_]*", type = { "keyword", "keyword2" } }, + { pattern = "union%s()[%a_][%w_]*", type = { "keyword", "keyword2" } }, + { pattern = "namespace%s()[%a_][%w_]*", type = { "keyword", "keyword2" } }, + -- static declarations + { + pattern = "static()%s+()inline", + type = { "keyword", "normal", "keyword" } + }, + { + pattern = "static()%s+()const", + type = { "keyword", "normal", "keyword" } + }, + { + pattern = "static()%s+()[%a_][%w_]*", + type = { "keyword", "normal", "literal" } + }, + -- match method type declarations + { + pattern = "[%a_][%w_]*()%s*()%**()%s*()[%a_][%w_]*()%s*()::", + type = { + "literal", "normal", "operator", "normal", + "literal", "normal", "operator" + } + }, + -- match function type declarations + { + pattern = "[%a_][%w_]*()%*+()%s+()[%a_][%w_]*%f[%(]", + type = { "literal", "operator", "normal", "function" } + }, + { + pattern = "[%a_][%w_]*()%s+()%*+()[%a_][%w_]*%f[%(]", + type = { "literal", "normal", "operator", "function" } + }, + { + pattern = "[%a_][%w_]*()%s+()[%a_][%w_]*%f[%(]", + type = { "literal", "normal", "function" } + }, + -- match variable type declarations + { + pattern = "[%a_][%w_]*()%*+()%s+()[%a_][%w_]*", + type = { "literal", "operator", "normal", "normal" } + }, + { + pattern = "[%a_][%w_]*()%s+()%*+()[%a_][%w_]*", + type = { "literal", "normal", "operator", "normal" } + }, + { + pattern = "[%a_][%w_]*()%s+()[%a_][%w_]*()%s*()[;,%[%)]", + type = { "literal", "normal", "normal", "normal", "normal" } + }, + { + pattern = "[%a_][%w_]*()%s+()[%a_][%w_]*()%s*()=", + type = { "literal", "normal", "normal", "normal", "operator" } + }, + { + pattern = "[%a_][%w_]*()&()%s+()[%a_][%w_]*", + type = { "literal", "operator", "normal", "normal" } + }, + { + pattern = "[%a_][%w_]*()%s+()&()[%a_][%w_]*", + type = { "literal", "normal", "operator", "normal" } + }, + -- Match scope operator element access + { + pattern = "[%a_][%w_]*()%s*()::", + type = { "literal", "normal", "operator" } + }, + -- Uppercase constants of at least 2 chars in len + { + pattern = "_?%u[%u_][%u%d_]*%f[%s%+%*%-%.%)%]}%?%^%%=/<>~|&;:,!]", + type = "number" + }, + -- Magic constants + { pattern = "__[%u%l]+__", type = "number" }, + -- all other functions + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + -- Macros + { + pattern = "^%s*#%s*define%s+()[%a_][%a%d_]*", + type = { "keyword", "symbol" } + }, + { + pattern = "#%s*include%s+()<.->", + type = { "keyword", "string" } + }, + { pattern = "%f[#]#%s*[%a_][%w_]*", type = "keyword" }, + -- Everything else to make the tokenizer work properly + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["alignof"] = "keyword", + ["alignas"] = "keyword", + ["and"] = "keyword", + ["and_eq"] = "keyword", + ["not"] = "keyword", + ["not_eq"] = "keyword", + ["or"] = "keyword", + ["or_eq"] = "keyword", + ["xor"] = "keyword", + ["xor_eq"] = "keyword", + ["private"] = "keyword", + ["protected"] = "keyword", + ["public"] = "keyword", + ["register"] = "keyword", + ["nullptr"] = "keyword", + ["operator"] = "keyword", + ["asm"] = "keyword", + ["bitand"] = "keyword", + ["bitor"] = "keyword", + ["catch"] = "keyword", + ["throw"] = "keyword", + ["try"] = "keyword", + ["class"] = "keyword", + ["compl"] = "keyword", + ["explicit"] = "keyword", + ["export"] = "keyword", + ["concept"] = "keyword", + ["consteval"] = "keyword", + ["constexpr"] = "keyword", + ["constinit"] = "keyword", + ["const_cast"] = "keyword", + ["dynamic_cast"] = "keyword", + ["reinterpret_cast"] = "keyword", + ["static_cast"] = "keyword", + ["static_assert"] = "keyword", + ["template"] = "keyword", + ["this"] = "keyword", + ["thread_local"] = "keyword", + ["requires"] = "keyword", + ["co_wait"] = "keyword", + ["co_return"] = "keyword", + ["co_yield"] = "keyword", + ["decltype"] = "keyword", + ["delete"] = "keyword", + ["friend"] = "keyword", + ["typeid"] = "keyword", + ["typename"] = "keyword", + ["mutable"] = "keyword", + ["override"] = "keyword", + ["virtual"] = "keyword", + ["using"] = "keyword", + ["namespace"] = "keyword", + ["new"] = "keyword", + ["noexcept"] = "keyword", + ["if"] = "keyword", + ["then"] = "keyword", + ["else"] = "keyword", + ["elseif"] = "keyword", + ["do"] = "keyword", + ["while"] = "keyword", + ["for"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["return"] = "keyword", + ["goto"] = "keyword", + ["struct"] = "keyword", + ["union"] = "keyword", + ["typedef"] = "keyword", + ["enum"] = "keyword", + ["extern"] = "keyword", + ["static"] = "keyword", + ["volatile"] = "keyword", + ["const"] = "keyword", + ["inline"] = "keyword", + ["case"] = "keyword", + ["default"] = "keyword", + ["auto"] = "keyword", + ["void"] = "keyword2", + ["int"] = "keyword2", + ["short"] = "keyword2", + ["long"] = "keyword2", + ["float"] = "keyword2", + ["double"] = "keyword2", + ["char"] = "keyword2", + ["unsigned"] = "keyword2", + ["bool"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + ["NULL"] = "literal", + ["wchar_t"] = "keyword2", + ["char8_t"] = "keyword2", + ["char16_t"] = "keyword2", + ["char32_t"] = "keyword2", + ["#include"] = "keyword", + ["#if"] = "keyword", + ["#ifdef"] = "keyword", + ["#ifndef"] = "keyword", + ["#elif"] = "keyword", + ["#else"] = "keyword", + ["#elseif"] = "keyword", + ["#endif"] = "keyword", + ["#define"] = "keyword", + ["#warning"] = "keyword", + ["#error"] = "keyword", + ["#pragma"] = "keyword", + ["end"] = "keyword", + ["element"] = "keyword", + ["label"] = "keyword", + ["measure"] = "keyword", + ["mesure"] = "keyword", + ["Element"] = "keyword", + ["whoinElement"] = "keyword", + ["region"] = "keyword", + ["R3"] = "keyword", + ["vertex"] = "keyword", + ["im"] = "keyword", + ["l1"] = "keyword", + ["l2"] = "keyword", + ["linfty"] = "keyword", + ["max"] = "keyword", + ["min"] = "keyword", + ["re"] = "keyword", + ["sum"] = "keyword", + ["quantile"] = "keyword", + ["sort"] = "keyword", + ["x"] = "keyword", + ["y"] = "keyword", + ["z"] = "keyword", + ["length"] = "keyword", + ["area"] = "keyword", + ["coef"] = "keyword", + ["diag"] = "keyword", + ["m"] = "keyword", + ["n"] = "keyword", + ["nbcoef"] = "keyword", + ["nnz"] = "keyword", + ["resize"] = "keyword", + ["size"] = "keyword", + ["imax"] = "keyword", + ["imin"] = "keyword", + ["N"] = "keyword", + ["P"] = "keyword", + ["nuTriangle"] = "keyword", + ["ndof"] = "keyword", + ["ndofK"] = "keyword", + ["nt"] = "keyword", + ["be"] = "keyword", + ["hmax"] = "keyword", + ["hmin"] = "keyword", + ["nbe"] = "keyword", + ["nv"] = "keyword", + ["bordermesure"] = "keyword", + ["eof"] = "keyword", + ["good"] = "keyword", + ["fixed"] = "keyword", + ["flush"] = "keyword", + ["noshowbase"] = "keyword", + ["noshowpos"] = "keyword", + ["precision"] = "keyword", + ["scientific"] = "keyword", + ["seekp"] = "keyword", + ["showbase"] = "keyword", + ["showpos"] = "keyword", + ["tellp"] = "keyword", + ["ARGV"] = "keyword", + ["CG"] = "keyword", + ["CPUTime"] = "keyword", + ["Cholesky"] = "keyword", + ["Cofactor"] = "keyword", + ["Crout"] = "keyword", + ["Edge03d"] = "keyword", + ["GMRES"] = "keyword", + ["HaveUMFPACK"] = "keyword", + ["LU"] = "keyword", + ["NaN"] = "keyword", + ["P0"] = "keyword", + ["P03d"] = "keyword", + ["P0VF"] = "keyword", + ["P0edge"] = "keyword", + ["P1"] = "keyword", + ["P13d"] = "keyword", + ["P1b"] = "keyword", + ["P1b3d"] = "keyword", + ["P1dc"] = "keyword", + ["P1nc"] = "keyword", + ["P2"] = "keyword", + ["P23d"] = "keyword", + ["P2b"] = "keyword", + ["P2dc"] = "keyword", + ["P2h"] = "keyword", + ["RT0"] = "keyword", + ["RT03d"] = "keyword", + ["RT0Ortho"] = "keyword", + ["RTmodif"] = "keyword", + ["UMFPACK"] = "keyword", + ["append"] = "keyword", + ["binary"] = "keyword", + ["hTriangle"] = "keyword", + ["havesparsesolver"] = "keyword", + ["inside"] = "keyword", + ["lenEdge"] = "keyword", + ["nTonEdge"] = "keyword", + ["nuEdge"] = "keyword", + ["pi"] = "keyword", + ["qf1pE"] = "keyword", + ["qf1pElump"] = "keyword", + ["qf1pT"] = "keyword", + ["qf1pTlump"] = "keyword", + ["qf2pE"] = "keyword", + ["qf2pT"] = "keyword", + ["qf2pT4P1"] = "keyword", + ["qf3pE"] = "keyword", + ["qf4pE"] = "keyword", + ["qf5pE"] = "keyword", + ["qf5pT"] = "keyword", + ["qf7pT"] = "keyword", + ["qf9pT"] = "keyword", + ["qfV1"] = "keyword", + ["qfV1lump"] = "keyword", + ["qfV2"] = "keyword", + ["qfV5"] = "keyword", + ["searchMethod"] = "keyword", + ["sparsesolver"] = "keyword", + ["sparsesolverSym"] = "keyword", + ["storagetotal"] = "keyword", + ["storageused"] = "keyword", + ["verbosity"] = "keyword", + ["version"] = "keyword", + ["volume"] = "keyword", + ["volumelevelset"] = "keyword", + ["wait"] = "keyword", + ["ShowAlloc"] = "keyword", + ["Newton"] = "keyword", + ["NoGraphicWindow"] = "keyword", + ["NoUseOfWait"] = "keyword", + ["SameMesh"] = "keyword", + ["Unique"] = "keyword", + ["arealevelset"] = "keyword", + ["average"] = "keyword", + ["chtmpdir"] = "keyword", + ["time"] = "keyword", + ["fill"] = "keyword", + ["value"] = "keyword", + ["nbiso"] = "keyword", + ["coeff"] = "keyword", + ["dataname"] = "keyword", + ["order"] = "keyword", + ["mpirank"] = "keyword", + ["mpiCommWorld"] = "keyword", + ["mpiGroup"] = "keyword", + ["mpiRequest"] = "keyword", + ["sparams"] = "keyword", + ["mpisize"] = "keyword", + ["mpiUndefined"] = "keyword", + ["mpiAnySource"] = "keyword", + ["communicator"] = "keyword", + ["worker"] = "keyword", + ["dim"] = "keyword", + ["cmm"] = "keyword", + ["solver"] = "keyword", + ["aniso"] = "keyword", + ["nbvx"] = "keyword", + ["abserror"] = "keyword", + ["anisomax"] = "keyword", + ["cutoff"] = "keyword", + ["err"] = "keyword", + ["errg"] = "keyword", + ["inquire"] = "keyword", + ["IsMetric"] = "keyword", + ["iso"] = "keyword", + ["keepbackvertices"] = "keyword", + ["maxsubdiv"] = "keyword", + ["metric"] = "keyword", + ["nbjacoby"] = "keyword", + ["nbsmooth"] = "keyword", + ["nomeshgeneration"] = "keyword", + ["omega"] = "keyword", + ["periodic"] = "keyword", + ["powerin"] = "keyword", + ["ratio"] = "keyword", + ["rescaling"] = "keyword", + ["splitin2"] = "keyword", + ["splitpbedge"] = "keyword", + ["thetamax"] = "keyword", + ["uniform"] = "keyword", + ["fixedborder"] = "keyword", + ["flags"] = "keyword", + ["ivalue"] = "keyword", + ["maxit"] = "keyword", + ["mode"] = "keyword", + ["ncv"] = "keyword", + ["nev"] = "keyword", + ["rawvector"] = "keyword", + ["sigma"] = "keyword", + ["sym"] = "keyword", + ["tol"] = "keyword", + ["vector"] = "keyword", + ["which"] = "keyword", + ["op"] = "keyword", + ["t"] = "keyword", + ["eps"] = "keyword", + ["nbiter"] = "keyword", + ["precon"] = "keyword", + ["veps"] = "keyword", + ["tgv"] = "keyword", + ["tolpivot"] = "keyword", + ["meditff"] = "keyword", + ["save"] = "keyword", + ["orientation"] = "keyword", + ["ptmerge"] = "keyword", + ["transfo"] = "keyword", + ["optimize"] = "keyword", + ["aspectratio"] = "keyword", + ["bb"] = "keyword", + ["boundary"] = "keyword", + ["bw"] = "keyword", + ["cut"] = "keyword", + ["grey"] = "keyword", + ["hsv"] = "keyword", + ["nbarrow"] = "keyword", + ["ps"] = "keyword", + ["varrow"] = "keyword", + ["viso"] = "keyword", + ["init"] = "keyword", + ["strategy"] = "keyword", + ["tolpivotsym"] = "keyword", + ["facetcl"] = "keyword", + ["holelist"] = "keyword", + ["nboffacetcl"] = "keyword", + ["nbofregions"] = "keyword", + ["regionlist"] = "keyword", + ["switch"] = "keyword", + ["refface"] = "keyword", + ["split"] = "keyword", + ["zbound"] = "keyword", + ["labeldown"] = "keyword", + ["labelmid"] = "keyword", + ["labelup"] = "keyword", + ["opt"] = "keyword", + ["mpiMAX"] = "keyword", + ["mpiMIN"] = "keyword", + ["mpiSUM"] = "keyword", + ["mpiPROD"] = "keyword", + ["mpiLAND"] = "keyword", + ["mpiLOR"] = "keyword", + ["mpiLXOR"] = "keyword", + ["mpiBAND"] = "keyword", + ["mpiBXOR"] = "keyword", + ["border"] = "keyword2", + ["Cmapmatrix"] = "keyword2", + ["Cmatrix"] = "keyword2", + ["complex"] = "keyword2", + ["fespace"] = "keyword2", + ["func"] = "keyword2", + ["ifstream"] = "keyword2", + ["mapmatrix"] = "keyword2", + ["matrix"] = "keyword2", + ["mesh"] = "keyword2", + ["mesh3"] = "keyword2", + ["ofstream"] = "keyword2", + ["problem"] = "keyword2", + ["real"] = "keyword2", + ["solve"] = "keyword2", + ["string"] = "keyword2", + ["varf"] = "keyword2", + ["macro"] = "keyword2", + ["dmatrix"] = "keyword2", + ["adj"] = "function", + ["find"] = "function", + ["rfind"] = "function", + ["seekg"] = "function", + ["tellg"] = "function", + ["AddLayers"] = "function", + ["AffineCG"] = "function", + ["AffineGMRES"] = "function", + ["BFGS"] = "function", + ["EigenValue"] = "function", + ["LinearCG"] = "function", + ["LinearGMRES"] = "function", + ["NLCG"] = "function", + ["abs"] = "function", + ["acos"] = "function", + ["acosh"] = "function", + ["adaptmesh"] = "function", + ["arg"] = "function", + ["asin"] = "function", + ["asinh"] = "function", + ["assert"] = "function", + ["atan"] = "function", + ["atan2"] = "function", + ["atanh"] = "function", + ["atof"] = "function", + ["atoi"] = "function", + ["boundingbox"] = "function", + ["buildmesh"] = "function", + ["buildmeshborder"] = "function", + ["ceil"] = "function", + ["change"] = "function", + ["checkmovemesh"] = "function", + ["clock"] = "function", + ["complexEigenValue"] = "function", + ["conj"] = "function", + ["convect"] = "function", + ["cos"] = "function", + ["cosh"] = "function", + ["defaultoUMFPACK"] = "function", + ["defaultsolver"] = "function", + ["defaulttoCG"] = "function", + ["defaulttoGMRES"] = "function", + ["defaulttoUMFPACK"] = "function", + ["det"] = "function", + ["dumptable"] = "function", + ["dx"] = "function", + ["dxx"] = "function", + ["dxy"] = "function", + ["dxz"] = "function", + ["dy"] = "function", + ["dyx"] = "function", + ["dyy"] = "function", + ["dyz"] = "function", + ["dz"] = "function", + ["dzx"] = "function", + ["dzy"] = "function", + ["dzz"] = "function", + ["emptymesh"] = "function", + ["erf"] = "function", + ["erfc"] = "function", + ["exec"] = "function", + ["exit"] = "function", + ["exp"] = "function", + ["floor"] = "function", + ["getline"] = "function", + ["hypot"] = "function", + ["imag"] = "function", + ["int1d"] = "function", + ["int2d"] = "function", + ["int3d"] = "function", + ["intallVFedges"] = "function", + ["intalledges"] = "function", + ["intallfaces"] = "function", + ["interplotematrix"] = "function", + ["interpolate"] = "function", + ["isInf"] = "function", + ["isNaN"] = "function", + ["isNormal"] = "function", + ["j0"] = "function", + ["j1"] = "function", + ["jn"] = "function", + ["jump"] = "function", + ["lgamma"] = "function", + ["log"] = "function", + ["log10"] = "function", + ["lrint"] = "function", + ["lround"] = "function", + ["ltime"] = "function", + ["mean"] = "function", + ["movemesh"] = "function", + ["newconvect"] = "function", + ["norm"] = "function", + ["on"] = "function", + ["otherside"] = "function", + ["plot"] = "function", + ["polar"] = "function", + ["pow"] = "function", + ["randinit"] = "function", + ["randint31"] = "function", + ["randint32"] = "function", + ["randreal1"] = "function", + ["randreal2"] = "function", + ["randreal3"] = "function", + ["randres53"] = "function", + ["readmesh"] = "function", + ["readmesh3"] = "function", + ["renumbering"] = "function", + ["restrict"] = "function", + ["rint"] = "function", + ["round"] = "function", + ["savemesh"] = "function", + ["savesurfacemesh"] = "function", + ["set"] = "function", + ["setw"] = "function", + ["showCPU"] = "function", + ["sin"] = "function", + ["sinh"] = "function", + ["splitmesh"] = "function", + ["sqr"] = "function", + ["sqrt"] = "function", + ["square"] = "function", + ["system"] = "function", + ["tan"] = "function", + ["tanh"] = "function", + ["tgamma"] = "function", + ["toCarray"] = "function", + ["toRarray"] = "function", + ["toZarray"] = "function", + ["trace"] = "function", + ["triangulate"] = "function", + ["trunc"] = "function", + ["y0"] = "function", + ["y1"] = "function", + ["yn"] = "function", + ["savevtk"] = "function", + ["mshmet"] = "function", + ["savesol"] = "function", + ["gmshload"] = "function", + ["gmshload3"] = "function", + ["mpiBarrier"] = "function", + ["mpiSize"] = "function", + ["Irecv"] = "function", + ["Isend"] = "function", + ["processor"] = "function", + ["mpiWaitAny"] = "function", + ["mpiWait"] = "function", + ["mpiRank"] = "function", + ["metis"] = "function", + ["metisdual"] = "function", + ["broadcast"] = "function", + ["scotch"] = "function", + ["parmetis"] = "function", + ["mpiWtime"] = "function", + ["buildlayers"] = "function", + ["mmg3d"] = "function", + ["processorblock"] = "function", + ["mpiWaitAll"] = "function", + ["mpiWtick"] = "function", + ["Send"] = "function", + ["Recv"] = "function", + ["mpiAlltoall"] = "function", + ["mpiGather"] = "function", + ["mpiScatter"] = "function", + ["mpiReduce"] = "function", + ["mpiAllReduce"] = "function", + ["mpiReduceScatter"] = "function", + }, +} diff --git a/debian/extra/plugins/language_ejs.lua b/debian/extra/plugins/language_ejs.lua new file mode 100644 index 0000000..f303bad --- /dev/null +++ b/debian/extra/plugins/language_ejs.lua @@ -0,0 +1,51 @@ +-- mod-version:3 + +-- Embedded JavaScript templating +-- provides .ejs syntax support (fork of language_html.lua). + +local syntax = require "core.syntax" + +syntax.add { + name = "EJS", + files = { "%.ejs$" }, + block_comment = { "" }, + patterns = { + { + pattern = { + "<%%", + "%%>" + }, + syntax = '.js', + type = "function" + }, + { + pattern = { + "<%s*[sS][cC][rR][iI][pP][tT]%f[%s>].->", + "<%s*/%s*[sS][cC][rR][iI][pP][tT]%s*>" + }, + syntax = ".js", + type = "function" + }, + { + pattern = { + "<%s*[sS][tT][yY][lL][eE]%f[%s>].->", + "<%s*/%s*[sS][tT][yY][lL][eE]%s*>" + }, + syntax = ".css", + type = "function" + }, + { pattern = { "" }, type = "comment" }, + { pattern = { '%f[^>][^<]', '%f[<]' }, type = "normal" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "%f[^<]![%a_][%w_]*", type = "keyword2" }, + { pattern = "%f[^<][%a_][%w_]*", type = "function" }, + { pattern = "%f[^<]/[%a_][%w_]*", type = "function" }, + { pattern = "[%a_][%w_]*", type = "keyword" }, + { pattern = "[/<>=]", type = "operator" }, + }, + symbols = {}, +} diff --git a/debian/extra/plugins/language_elixir.lua b/debian/extra/plugins/language_elixir.lua new file mode 100644 index 0000000..49da053 --- /dev/null +++ b/debian/extra/plugins/language_elixir.lua @@ -0,0 +1,95 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Elixir", + files = { "%.ex$", "%.exs$"}, + comment = "#", + patterns = { + { pattern = "#.*\n", type = "comment" }, + { pattern = { ':"', '"', '\\' }, type = "number" }, + { pattern = { '"""', '"""', '\\' }, type = "string" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { '~%a"""', '"""' }, type = "string" }, + { pattern = { '~%a[/"|\'%(%[%{<]', '[/"|\'%)%]%}>]', '\\' }, type = "string"}, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = ':"?[%a_][%w_]*"?', type = "number" }, + { pattern = "[%a][%w_!?]*%f[(]", type = "function" }, + { pattern = "%u%w+", type = "normal" }, + { pattern = "@[%a_][%w_]*", type = "keyword2" }, + { pattern = "_%a[%w_]*", type = "keyword2" }, + { pattern = "[%+%-=/%*<>!|&]", type = "operator" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["def"] = "keyword", + ["defp"] = "keyword", + ["defguard"] = "keyword", + ["defguardp"] = "keyword", + ["defmodule"] = "keyword", + ["defprotocol"] = "keyword", + ["defimpl"] = "keyword", + ["defrecord"] = "keyword", + ["defrecordp"] = "keyword", + ["defmacro"] = "keyword", + ["defmacrop"] = "keyword", + ["defdelegate"] = "keyword", + ["defoverridable"] = "keyword", + ["defexception"] = "keyword", + ["defcallback"] = "keyword", + ["defstruct"] = "keyword", + ["for"] = "keyword", + ["case"] = "keyword", + ["when"] = "keyword", + ["with"] = "keyword", + ["cond"] = "keyword", + ["if"] = "keyword", + ["unless"] = "keyword", + ["try"] = "keyword", + ["receive"] = "keyword", + ["after"] = "keyword", + ["raise"] = "keyword", + ["rescue"] = "keyword", + ["catch"] = "keyword", + ["else"] = "keyword", + ["quote"] = "keyword", + ["unquote"] = "keyword", + ["super"] = "keyword", + ["unquote_splicing"] = "keyword", + ["do"] = "keyword", + ["end"] = "keyword", + ["fn"] = "keyword", + ["import"] = "keyword2", + ["alias"] = "keyword2", + ["use"] = "keyword2", + ["require"] = "keyword2", + ["and"] = "operator", + ["or"] = "operator", + ["true"] = "literal", + ["false"] = "literal", + ["nil"] = "literal", + }, +} + +syntax.add { + files = { "%.l?eex$", "%.h?eex$" }, + patterns = { + { pattern = { "" }, type = "comment" }, + { pattern = { '%f[^>][^<]', '%f[<]' }, type = "normal" }, + { pattern = { '<%%=?', '%%>' }, type = "normal" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "%f[^<]![%a_][%w_]*", type = "keyword2" }, + { pattern = "%f[^<][%a_][%w_]*", type = "function" }, + { pattern = "%f[^<]/[%a_][%w_]*", type = "function" }, + { pattern = "[%a_][%w_]*", type = "keyword" }, + { pattern = "[/<>=]", type = "operator" }, + }, + symbols = {}, +} diff --git a/debian/extra/plugins/language_elm.lua b/debian/extra/plugins/language_elm.lua new file mode 100644 index 0000000..2d33813 --- /dev/null +++ b/debian/extra/plugins/language_elm.lua @@ -0,0 +1,49 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Elm", + files = { "%.elm$" }, + comment = "%-%-", + patterns = { + { pattern = {"%-%-", "\n"}, type = "comment" }, + { pattern = { "{%-", "%-}" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { '"""', '"""', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "%.%.", type = "operator" }, + { pattern = "[=:|&<>%+%-%*\\/%^%%]", type = "operator" }, + { pattern = "[%a_'][%w_']*", type = "symbol" }, + }, + symbols = { + ["as"] = "keyword", + ["case"] = "keyword", + ["of"] = "keyword", + ["if"] = "keyword", + ["then"] = "keyword", + ["else"] = "keyword", + ["import"] = "keyword", + ["module"] = "keyword", + ["exposing"] = "keyword", + ["let"] = "keyword", + ["in"] = "keyword", + ["type"] = "keyword", + ["alias"] = "keyword", + ["port"] = "keyword", + ["and"] = "keyword", + ["or"] = "keyword", + ["xor"] = "keyword", + ["not"] = "keyword", + ["number"] = "keyword2", + ["Bool"] = "keyword2", + ["Char"] = "keyword2", + ["Float"] = "keyword2", + ["Int"] = "keyword2", + ["String"] = "keyword2", + ["True"] = "literal", + ["False"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_env.lua b/debian/extra/plugins/language_env.lua new file mode 100644 index 0000000..bcdb8f1 --- /dev/null +++ b/debian/extra/plugins/language_env.lua @@ -0,0 +1,68 @@ +-- mod-version:3 + +local syntax = require "core.syntax" + +local key_pattern = '[a-zA-Z_]+[a-zA-Z0-9_]*' +local unicode_sequence = "'?\\u%x%x%x%x'?" +local escaped_literals = "\\[nrtfb\\\"']" +local null_pattern = '%s*[Nn][Uu][Ll][Ll]%s*' +local true_pattern = '%s*[Tt][Rr][Uu][Ee]%s*' +local false_pattern = '%s*[Ff][Aa][Ll][Ss][Ee]%s*' + +local synt_key = { + symbols = {}, + patterns = { + { type = "keyword2", pattern = key_pattern }, + }, +} + +local synt_dqs = { + symbols = {}, + patterns = { + { pattern = { "%${", "}" }, type = "keyword", syntax = synt_key }, + { pattern = "0[bB][%d]+", type = "number" }, + { pattern = "0[xX][%da-fA-F]+", type = "number" }, + { pattern = "[-+]?%.?%d+", type = "number" }, + { pattern = escaped_literals, type = "literal" }, -- escaped chars + { pattern = unicode_sequence, type = "literal" }, -- unicode sequence + { pattern = '[%w%p%s]', type = "string" }, + }, +} + +syntax.add { + name = "language_env", + files = { "%.env$" }, + comment = '#', + symbols = {}, + patterns = { + { pattern = "#.*$", type = "comment" }, + { pattern = "export", type = "function" }, + { pattern = null_pattern, type = "literal" }, + { pattern = true_pattern, type = "literal" }, + { pattern = false_pattern, type = "literal" }, + { pattern = escaped_literals, type = "literal" }, + { pattern = unicode_sequence, type = "literal" }, + -- interpolation + { pattern = { "%${", "}" }, type = "keyword", syntax = synt_key }, + -- numbers + { pattern = "0[bB][%d]+", type = "number" }, + { pattern = "0[xX][%da-fA-F]+", type = "number" }, + { pattern = "[-+]?%.?%d+", type = "number" }, + -- keys + { pattern = '[\'"].*[\'"]%s*=.*', type = "normal" }, + -- { + -- pattern = '[\'"]?'..escaped_literals..'[\'"]?%s*=.*', + -- type = "normal" + -- }, + -- { + -- pattern = '[\'"]?'..null_pattern..'[\'"]?%s*=.*', + -- type = "normal" + -- }, + { pattern = key_pattern..'%s*()=%s*', type = { "keyword2", "operator" }}, + -- quoted strings + { pattern = {'"', '"', '\\'}, type = "string", syntax = synt_dqs}, + { pattern = {"'", "'", '\\'}, type = "string" }, + { pattern = {'"""', '"""', '\\'}, type = "string" }, + { pattern = {"'''", "'''", '\\'}, type = "string" }, + }, +} diff --git a/debian/extra/plugins/language_erb.lua b/debian/extra/plugins/language_erb.lua new file mode 100644 index 0000000..bc52cfd --- /dev/null +++ b/debian/extra/plugins/language_erb.lua @@ -0,0 +1,55 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "html-eruby", + files = { PATHSEP .. "%.html?%.erb$", "%.erb$" }, + block_comment = { "" }, + patterns = { + { + pattern = { + "<%s*[sS][cC][rR][iI][pP][tT]%f[%s>].->", + "<%s*/%s*[sS][cC][rR][iI][pP][tT]%s*>" + }, + syntax = ".js", + type = "function" + }, + { + pattern = { + "<%s*[sS][tT][yY][lL][eE]%f[%s>].->", + "<%s*/%s*[sS][tT][yY][lL][eE]%s*>" + }, + syntax = ".css", + type = "function" + }, + { + pattern = { + "<%%", + "%%>" + }, + syntax = ".rb", + type = "function" + }, + { + pattern = { + "<%%=", + "%%>" + }, + syntax = ".rb", + type = "function" + }, + { pattern = { "" }, type = "comment" }, + { pattern = { '%f[^>][^<]', '%f[<]' }, type = "normal" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "%f[^<]![%a_][%w_]*", type = "keyword2" }, + { pattern = "%f[^<][%a_][%w_]*", type = "function" }, + { pattern = "%f[^<]/[%a_][%w_]*", type = "function" }, + { pattern = "[%a_][%w_]*", type = "keyword" }, + { pattern = "[/<>=]", type = "operator" }, + }, + symbols = {}, +} diff --git a/debian/extra/plugins/language_fe.lua b/debian/extra/plugins/language_fe.lua new file mode 100644 index 0000000..041512f --- /dev/null +++ b/debian/extra/plugins/language_fe.lua @@ -0,0 +1,52 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "fe", + files = "%.fe$", + comment = ";", + patterns = { + { pattern = ";.*", type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "'", type = "symbol" }, + { pattern = "=", type = "symbol" }, + { pattern = "<=?", type = "symbol" }, + { pattern = "[%+-%*/]", type = "symbol" }, + { pattern = "%f[^(][^()'%s\"]+", type = "function" }, + { pattern = "[^()'%s\"]+", type = "symbol" }, + }, + symbols = { + ["let"] = "keyword", + ["if"] = "keyword", + ["fn"] = "keyword", + ["mac"] = "keyword", + ["while"] = "keyword", + ["quote"] = "keyword", + ["'"] = "keyword", + ["and"] = "keyword", + ["or"] = "keyword", + ["do"] = "keyword", + ["cons"] = "keyword", + ["car"] = "keyword", + ["cdr"] = "keyword", + ["setcar"] = "keyword", + ["setcdr"] = "keyword", + ["list"] = "keyword", + ["not"] = "keyword", + ["is"] = "keyword", + ["atom"] = "keyword", + ["print"] = "keyword", + ["<"] = "operator", + ["<="] = "operator", + ["="] = "operator", + ["+"] = "operator", + ["-"] = "operator", + ["*"] = "operator", + ["/"] = "operator", + ["nil"] = "literal", + ["t"] = "literal", + } +} diff --git a/debian/extra/plugins/language_fennel.lua b/debian/extra/plugins/language_fennel.lua new file mode 100644 index 0000000..dcfd245 --- /dev/null +++ b/debian/extra/plugins/language_fennel.lua @@ -0,0 +1,268 @@ +-- mod-version:3 +-- Support for the Fennel programming language: https://fennel-lang.org +-- Covers all the keywords up to Fennel version 1.2.0 + +-- Currently only covers highlighting, not indentation, delimiter +-- matching, or evaluation. + +local syntax = require("core.syntax") + +syntax.add({ + comment = ";", + files = "%.fnl$", + name = "Fennel", + patterns = { + { pattern = ";.-\n", type = "comment" }, + { pattern = { '"', '"', "\\" }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "%f[^(][^()'%s\"]+", type = "function" }, + { pattern = "[^()'%s\"]+", type = "symbol" }, + }, + symbols = { + ["#"] = "keyword", + ["%"] = "keyword", + ["*"] = "keyword", + ["+"] = "keyword", + ["-"] = "keyword", + ["->"] = "keyword", + ["->>"] = "keyword", + ["-?>"] = "keyword", + ["-?>>"] = "keyword", + ["."] = "keyword", + [".."] = "keyword", + ["/"] = "keyword", + ["//"] = "keyword", + [":"] = "keyword", + ["<"] = "keyword", + ["<="] = "keyword", + ["="] = "keyword", + [">"] = "keyword", + [">="] = "keyword", + ["?."] = "keyword", + ["^"] = "keyword", + _G = "keyword", + accumulate = "keyword2", + ["and"] = "keyword2", + arg = "keyword2", + assert = "keyword2", + band = "keyword2", + bit32 = "keyword2", + ["bit32.arshift"] = "keyword2", + ["bit32.band"] = "keyword2", + ["bit32.bnot"] = "keyword2", + ["bit32.bor"] = "keyword2", + ["bit32.btest"] = "keyword2", + ["bit32.bxor"] = "keyword2", + ["bit32.extract"] = "keyword2", + ["bit32.lrotate"] = "keyword2", + ["bit32.lshift"] = "keyword2", + ["bit32.replace"] = "keyword2", + ["bit32.rrotate"] = "keyword2", + ["bit32.rshift"] = "keyword2", + bnot = "keyword2", + bor = "keyword2", + bxor = "keyword2", + collect = "keyword2", + collectgarbage = "keyword2", + comment = "keyword2", + coroutine = "keyword2", + ["coroutine.create"] = "keyword2", + ["coroutine.resume"] = "keyword2", + ["coroutine.running"] = "keyword2", + ["coroutine.status"] = "keyword2", + ["coroutine.wrap"] = "keyword2", + ["coroutine.yield"] = "keyword2", + debug = "keyword2", + ["debug.debug"] = "keyword2", + ["debug.gethook"] = "keyword2", + ["debug.getinfo"] = "keyword2", + ["debug.getlocal"] = "keyword2", + ["debug.getmetatable"] = "keyword2", + ["debug.getregistry"] = "keyword2", + ["debug.getupvalue"] = "keyword2", + ["debug.getuservalue"] = "keyword2", + ["debug.sethook"] = "keyword2", + ["debug.setlocal"] = "keyword2", + ["debug.setmetatable"] = "keyword2", + ["debug.setupvalue"] = "keyword2", + ["debug.setuservalue"] = "keyword2", + ["debug.traceback"] = "keyword2", + ["debug.upvalueid"] = "keyword2", + ["debug.upvaluejoin"] = "keyword2", + ["do"] = "keyword2", + dofile = "keyword2", + doto = "keyword2", + each = "keyword2", + error = "keyword2", + ["eval-compiler"] = "keyword2", + ["false"] = "literal", + fcollect = "keyword2", + fn = "keyword2", + ["for"] = "keyword2", + getmetatable = "keyword2", + global = "keyword2", + hashfn = "keyword2", + icollect = "keyword2", + ["if"] = "keyword2", + ["import-macros"] = "keyword2", + include = "keyword2", + io = "keyword2", + ["io.close"] = "keyword2", + ["io.flush"] = "keyword2", + ["io.input"] = "keyword2", + ["io.lines"] = "keyword2", + ["io.open"] = "keyword2", + ["io.output"] = "keyword2", + ["io.popen"] = "keyword2", + ["io.read"] = "keyword2", + ["io.tmpfile"] = "keyword2", + ["io.type"] = "keyword2", + ["io.write"] = "keyword2", + ipairs = "keyword2", + lambda = "keyword2", + length = "keyword2", + let = "keyword2", + load = "keyword2", + loadfile = "keyword2", + loadstring = "keyword2", + ["local"] = "keyword2", + lshift = "keyword2", + lua = "keyword2", + macro = "keyword2", + macrodebug = "keyword2", + macros = "keyword2", + match = "keyword2", + ["match-try"] = "keyword2", + math = "keyword2", + ["math.abs"] = "keyword2", + ["math.acos"] = "keyword2", + ["math.asin"] = "keyword2", + ["math.atan"] = "keyword2", + ["math.atan2"] = "keyword2", + ["math.ceil"] = "keyword2", + ["math.cos"] = "keyword2", + ["math.cosh"] = "keyword2", + ["math.deg"] = "keyword2", + ["math.exp"] = "keyword2", + ["math.floor"] = "keyword2", + ["math.fmod"] = "keyword2", + ["math.frexp"] = "keyword2", + ["math.ldexp"] = "keyword2", + ["math.log"] = "keyword2", + ["math.log10"] = "keyword2", + ["math.max"] = "keyword2", + ["math.min"] = "keyword2", + ["math.modf"] = "keyword2", + ["math.pow"] = "keyword2", + ["math.rad"] = "keyword2", + ["math.random"] = "keyword2", + ["math.randomseed"] = "keyword2", + ["math.sin"] = "keyword2", + ["math.sinh"] = "keyword2", + ["math.sqrt"] = "keyword2", + ["math.tan"] = "keyword2", + ["math.tanh"] = "keyword2", + module = "keyword2", + next = "keyword2", + ["nil"] = "literal", + ["not"] = "keyword2", + ["not="] = "keyword2", + ["or"] = "keyword2", + os = "keyword2", + ["os.clock"] = "keyword2", + ["os.date"] = "keyword2", + ["os.difftime"] = "keyword2", + ["os.execute"] = "keyword2", + ["os.exit"] = "keyword2", + ["os.getenv"] = "keyword2", + ["os.remove"] = "keyword2", + ["os.rename"] = "keyword2", + ["os.setlocale"] = "keyword2", + ["os.time"] = "keyword2", + ["os.tmpname"] = "keyword2", + package = "keyword2", + ["package.loadlib"] = "keyword2", + ["package.searchpath"] = "keyword2", + ["package.seeall"] = "keyword2", + pairs = "keyword2", + partial = "keyword2", + pcall = "keyword2", + ["pick-args"] = "keyword2", + ["pick-values"] = "keyword2", + print = "keyword2", + quote = "keyword2", + rawequal = "keyword2", + rawget = "keyword2", + rawlen = "keyword2", + rawset = "keyword2", + require = "keyword2", + ["require-macros"] = "keyword2", + rshift = "keyword2", + select = "keyword2", + set = "keyword2", + ["set-forcibly!"] = "keyword2", + setmetatable = "keyword2", + string = "keyword2", + ["string.byte"] = "keyword2", + ["string.char"] = "keyword2", + ["string.dump"] = "keyword2", + ["string.find"] = "keyword2", + ["string.format"] = "keyword2", + ["string.gmatch"] = "keyword2", + ["string.gsub"] = "keyword2", + ["string.len"] = "keyword2", + ["string.lower"] = "keyword2", + ["string.match"] = "keyword2", + ["string.rep"] = "keyword2", + ["string.reverse"] = "keyword2", + ["string.sub"] = "keyword2", + ["string.upper"] = "keyword2", + table = "keyword2", + ["table.concat"] = "keyword2", + ["table.insert"] = "keyword2", + ["table.maxn"] = "keyword2", + ["table.pack"] = "keyword2", + ["table.remove"] = "keyword2", + ["table.sort"] = "keyword2", + ["table.unpack"] = "keyword2", + tonumber = "keyword2", + tostring = "keyword2", + ["true"] = "literal", + tset = "keyword2", + type = "keyword2", + unpack = "keyword2", + values = "keyword2", + var = "keyword2", + when = "keyword2", + ["while"] = "keyword2", + ["with-open"] = "keyword2", + xpcall = "keyword2", + ["~="] = "keyword", + ["λ"] = "keyword", + }, +}) + +-- To regenerate the syntax from the compiler: +-- (macro s [] +-- (let [{: syntax} (require :fennel) +-- symbols {:nil :literal +-- :true :literal +-- :false :literal}] +-- `(syntax.add {:name "Fennel" +-- :files "%.fnl$" +-- :comment ";" +-- :patterns [{:type :comment :pattern ";.-\n"} +-- {:type :string :pattern {1 "\"" 2 "\"" 3 "\\"}} +-- {:type :number :pattern "0x[%da-fA-F]+"} +-- {:type :number :pattern "-?%d+[%d%.]*"} +-- {:type :number :pattern "-?%.?%d+"} +-- {:type :function :pattern "%f[^(][^()'%s\"]+"} +-- {:type :symbol :pattern "[^()'%s\"]+"}] +-- :symbols ,(collect [name (pairs (syntax)) :into symbols] +-- (values name +-- (if (name:find "[a-z]") +-- :keyword2 :keyword)))}))) (s) + +-- and reformat the output, of course diff --git a/debian/extra/plugins/language_fortran.lua b/debian/extra/plugins/language_fortran.lua new file mode 100644 index 0000000..da97a4c --- /dev/null +++ b/debian/extra/plugins/language_fortran.lua @@ -0,0 +1,85 @@ +-- Author: Rohan Vashisht: https://github.com/rohanvashisht1234/ + + +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Fortran", -- tested ok + files = { + "%.f$", -- tested ok + "%.f90$", -- tested ok + "%.f95$" -- tested ok + }, + comment = "!", -- tested ok + patterns = { + { pattern = { "'", "'", '\\' }, type = "string" }, -- tested ok + { pattern = { '"', '"', '\\' }, type = "string" }, -- tested ok + { pattern = "!.*", type = "comment" }, -- tested ok + { pattern = "%.[%a_][%w_]+%.", type = "normal" }, -- tested ok + { pattern = "[!%-/*?:=><+]", type = "operator" }, -- tested ok + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- tested ok + { pattern = "program()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "module()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "use()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "struct()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + + { pattern = "-?%d+[%d%.eE_]*", type = "number" }, -- tested ok + { pattern = "-?%.?%d+", type = "number" }, -- tested ok + { pattern = "[%a_][%w_]*", type = "normal" }, -- tested ok + }, + symbols = { + ["end"] = "keyword", -- tested ok + ["program"] = "keyword", -- tested ok + ["write"] = "keyword", -- tested ok + ["print"] = "keyword", -- tested ok + ["implicit"] = "keyword", -- tested ok + ["integer"] = "keyword", -- tested ok + ["real"] = "keyword", -- tested ok + ["complex"] = "keyword", -- tested ok + ["character"] = "keyword", -- tested ok + ["logical"] = "keyword", -- tested ok + ["allocatable"] = "keyword", -- tested ok + ["subroutine"] = "keyword", -- tested ok + ["do"] = "keyword", -- tested ok + ["call"] = "keyword", -- tested ok + ["extends"] = "keyword", -- tested ok + ["protected"] = "keyword", -- tested ok + ["contains"] = "keyword", -- tested ok + ["else"] = "keyword", -- tested ok + ["then"] = "keyword", -- tested ok + ["if"] = "keyword", -- tested ok + ["cycle"] = "keyword", -- tested ok + ["parameter"] = "keyword", -- tested ok + ["concurrent"] = "keyword", -- tested ok + ["function"] = "keyword", -- tested ok + ["private"] = "keyword", -- tested ok + ["public"] = "keyword", -- tested ok + ["module"] = "keyword", -- tested ok + ["use"] = "keyword", -- tested ok + ["type"] = "keyword", -- tested ok + ["sequence"] = "keyword", -- tested ok + ["struct"] = "keyword", -- tested ok + ["result"] = "keyword", -- tested ok + ["stop"] = "keyword", -- tested ok + ["only"] = "keyword", -- tested ok + + + ["none"] = "keyword2", -- tested ok + ["len"] = "keyword2", -- tested ok + + [".false."] = "keyword2", -- tested ok + [".true."] = "keyword2", -- tested ok + [".eq."] = "keyword2", -- tested ok + [".ne."] = "keyword2", -- tested ok + [".gt."] = "keyword2", -- tested ok + [".lt."] = "keyword2", -- tested ok + [".ge"] = "keyword2", -- tested ok + [".not."] = "keyword2", -- tested ok + [".le."] = "keyword2", -- tested ok + [".or."] = "keyword2", -- tested ok + [".and."] = "keyword2", -- tested ok + [".eqv."] = "keyword2", -- tested ok + [".neqv."] = "keyword2", -- tested ok + } +} diff --git a/debian/extra/plugins/language_fstab.lua b/debian/extra/plugins/language_fstab.lua new file mode 100644 index 0000000..5032cae --- /dev/null +++ b/debian/extra/plugins/language_fstab.lua @@ -0,0 +1,99 @@ +-- mod-version:3 + +local syntax = require "core.syntax" + +syntax.add { + name = "fstab", + files = { PATHSEP .. "fstab$" }, + comment = '#', + patterns = { + -- Only lines that start with a # are comments; you can have #'s in fuse + -- filesystem strings that aren't comments, so shouldn't be highlighted as such. + { regex = "^#.*", type = "comment" }, + { pattern = "[=/:.,]+", type = "operator" }, + { pattern = "/.*/", type = "string" }, + { pattern = "#", type = "operator" }, + -- { + -- pattern = "%g+%s+()%g+%s+()%g+%s+()%g+%s+()[01]%s+()[012]%s*", + -- type = { + -- -- filesystem + -- "keyword", + -- -- mount point + -- "keyword2", + -- -- fs type + -- "symbol", + -- -- options + -- "keyword2", + -- -- dump frequency + -- "keyword", + -- -- pass number + -- "keyword2", + -- } + -- }, + + -- UUID + { pattern = "%w-%-%w-%-%w-%-%w-%-%w- ", type = "string" }, + -- IPv4 Address + { pattern = "%d+%.%d+%.%d+%.%d+", type = "string" }, + + { pattern = " %d+ ", type = "number" }, + { pattern = "[%w_]+", type = "symbol" }, + + }, + symbols = { + ["none"] = "literal", + + ["LABEL"] = "keyword", + ["UUID"] = "keyword", + + -- filesystems + ["aufs"] = "keyword2", + ["autofs"] = "keyword2", + ["bdev"] = "keyword2", + ["binder"] = "keyword2", + ["binfmt_misc"] = "keyword2", + ["bpf"] = "keyword2", + ["btrfs"] = "keyword2", + ["cgroup"] = "keyword2", + ["cgroup2"] = "keyword2", + ["configfs"] = "keyword2", + ["cpuset"] = "keyword2", + ["debugfs"] = "keyword2", + ["devpts"] = "keyword2", + ["devtmpfs"] = "keyword2", + ["ecryptfs"] = "keyword2", + ["ext2"] = "keyword2", + ["ext3"] = "keyword2", + ["ext4"] = "keyword2", + ["fuse"] = "keyword2", + ["fuseblk"] = "keyword2", + ["fusectl"] = "keyword2", + ["hfs"] = "keyword2", + ["hfsplus"] = "keyword2", + ["hugetlbfs"] = "keyword2", + ["jfs"] = "keyword2", + ["minix"] = "keyword2", + ["mqueue"] = "keyword2", + ["msdos"] = "keyword2", + ["nfs"] = "keyword2", + ["nfs4"] = "keyword2", + ["nfsd"] = "keyword2", + ["ntfs"] = "keyword2", + ["pipefs"] = "keyword2", + ["proc"] = "keyword2", + ["pstore"] = "keyword2", + ["qnx4"] = "keyword2", + ["ramfs"] = "keyword2", + ["rpc_pipefs"] = "keyword2", + ["securityfs"] = "keyword2", + ["sockfs"] = "keyword2", + ["squashfs"] = "keyword2", + ["swap"] = "keyword2", + ["sysfs"] = "keyword2", + ["tmpfs"] = "keyword2", + ["tracefs"] = "keyword2", + ["ufs"] = "keyword2", + ["vfat"] = "keyword2", + ["xfs"] = "keyword2", + }, +} diff --git a/debian/extra/plugins/language_gabc.lua b/debian/extra/plugins/language_gabc.lua new file mode 100644 index 0000000..c07307b --- /dev/null +++ b/debian/extra/plugins/language_gabc.lua @@ -0,0 +1,19 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "GABC", + files = { "%.gabc$" }, + comment = "%%", + patterns = { + { pattern = "%%.*", type = "comment" }, + { pattern = "^%w+:", type = "keyword2" }, + { pattern = "[%*{}]", type = "operator" }, + { pattern = "<[^>]*>", type = "function" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = { "|", "%)" }, type = "keyword2" }, + { pattern = "%([^%)|]*%)?", type = "keyword" }, + }, + symbols = {} +} + diff --git a/debian/extra/plugins/language_gdscript.lua b/debian/extra/plugins/language_gdscript.lua new file mode 100644 index 0000000..d03dce8 --- /dev/null +++ b/debian/extra/plugins/language_gdscript.lua @@ -0,0 +1,101 @@ +-- mod-version:3 +-- Support for the GDScript programming language: https://godotengine.org/ +-- Covers the most used keywords up to Godot version 3.2.x + +local syntax = require "core.syntax" + +syntax.add { + name = "GDScript", + files = { "%.gd$" }, + comment = "#", + patterns = { + { pattern = "#.-\n", type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?0x%x*", type = "number" }, + { pattern = "-?%d+[%d%.e]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "[%+%:%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + -- keywords + ["if"] = "keyword", + ["elif"] = "keyword", + ["else"] = "keyword", + ["for"] = "keyword", + ["while"] = "keyword", + ["match"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["pass"] = "keyword", + ["return"] = "keyword", + ["class"] = "keyword", + ["class_name"] = "keyword", + ["extends"] = "keyword", + ["is"] = "keyword", + ["in"] = "keyword", + ["as"] = "keyword", + ["and"] = "keyword", + ["or"] = "keyword", + ["not"] = "keyword", + ["self"] = "keyword", + ["tool"] = "keyword", + ["signal"] = "keyword", + ["func"] = "keyword", + ["static"] = "keyword", + ["const"] = "keyword", + ["enum"] = "keyword", + ["var"] = "keyword", + ["onready"] = "keyword", + ["export"] = "keyword", + ["setget"] = "keyword", + ["breakpoint"] = "keyword", + ["preload"] = "keyword", + ["yield"] = "keyword", + ["assert"] = "keyword", + ["remote"] = "keyword", + ["master"] = "keyword", + ["puppet"] = "keyword", + ["remotesync"] = "keyword", + ["mastersync"] = "keyword", + ["puppetsync"] = "keyword", + -- types + ["void"] = "keyword2", + ["int"] = "keyword2", + ["float"] = "keyword2", + ["bool"] = "keyword2", + ["String"] = "keyword2", + ["Vector2"] = "keyword2", + ["Rect2"] = "keyword2", + ["Vector3"] = "keyword2", + ["Transform2D"] = "keyword2", + ["Plane"] = "keyword2", + ["Quat"] = "keyword2", + ["AABB"] = "keyword2", + ["Basis"] = "keyword2", + ["Transform"] = "keyword2", + ["Color"] = "keyword2", + ["NodePath"] = "keyword2", + ["RID"] = "keyword2", + ["Object"] = "keyword2", + ["Array"] = "keyword2", + ["PoolByteArray"] = "keyword2", + ["PoolIntArray"] = "keyword2", + ["PoolRealArray"] = "keyword2", + ["PoolStringArray"] = "keyword2", + ["PoolVector2Array"] = "keyword2", + ["PoolVector3Array"] = "keyword2", + ["PoolColorArray"] = "keyword2", + ["Dictionary"] = "keyword2", + -- literals + ["null"] = "literal", + ["true"] = "literal", + ["false"] = "literal", + ["PI"] = "literal", + ["TAU"] = "literal", + ["INF"] = "literal", + ["NAN"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_glsl.lua b/debian/extra/plugins/language_glsl.lua new file mode 100644 index 0000000..360e11f --- /dev/null +++ b/debian/extra/plugins/language_glsl.lua @@ -0,0 +1,389 @@ +-- mod-version:3 + +local style = require "core.style" +local common = require "core.common" + +local syntax = require "core.syntax" + +syntax.add { + name = "GLSL", + files = { "%.glsl$", "%.frag$", "%.vert$", }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { "#", "[^\\]\n" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + + { pattern = "ivec[2-4]", type = "keyword2" }, + { pattern = "bvec[2-4]", type = "keyword2" }, + { pattern = "uvec[2-4]", type = "keyword2" }, + { pattern = "vec[2-4]", type = "keyword2" }, + { pattern = "dmat[2-4]x[2-4]", type = "keyword2" }, + { pattern = "dmat[2-4]", type = "keyword2" }, + { pattern = "mat[2-4]x[2-4]", type = "keyword2" }, + { pattern = "mat[2-4]", type = "keyword2" }, + + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + --https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf + --The symbols are added here in the order they appear in the spec + ["if"] = "keyword", + ["else"] = "keyword", + ["do"] = "keyword", + ["while"] = "keyword", + ["for"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["return"] = "keyword", + ["const"] = "keyword", + ["switch"] = "keyword", + ["case"] = "keyword", + ["default"] = "keyword", + ["const"] = "keyword", + ["void"] = "keyword", + ["bool"] = "keyword2", + ["int"] = "keyword2", + ["uint"] = "keyword2", + ["float"] = "keyword2", + ["double"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + ["NULL"] = "literal", + + ["attribute"] = "keyword", + ["varying"] = "keyword", + ["uniform"] = "keyword", + ["buffer"] = "keyword", + ["shared"] = "keyword", + ["layout"] = "keyword", + ["centroid"] = "keyword", + ["flat"] = "keyword", + ["smooth"] = "keyword", + ["noperspective"]= "keyword", + ["patch"] = "keyword", + ["sample"] = "keyword", + ["in"] = "keyword", + ["out"] = "keyword", + ["inout"] = "keyword", + ["invariant"] = "keyword", + ["precise"] = "keyword", + ["lowp"] = "keyword", + ["mediump"] = "keyword", + ["highp"] = "keyword", + ["precision"] = "keyword", + ["struct"] = "keyword", + ["subroutine"] = "keyword", + + ["coherent"] = "keyword", + ["volatile"] = "keyword", + ["readonly"] = "keyword", + ["writeonly"] = "keyword", + + ["sampler1D"] = "keyword2", + ["sampler2D"] = "keyword2", + ["sampler3D"] = "keyword2", + ["samplerCube"] = "keyword2", + ["sampler1DShadow"] = "keyword2", + ["sampler2DShadow"] = "keyword2", + ["samplerCubeShadow"] = "keyword2", + ["sampler1DArray"] = "keyword2", + ["sampler2DArray"] = "keyword2", + ["samplerCubeArray"] = "keyword2", + ["sampler1DArrayShadow"] = "keyword2", + ["sampler2DArrayShadow"] = "keyword2", + ["samplerCubeArrayShadow"]= "keyword2", + ["isampler1D"] = "keyword2", + ["isampler2D"] = "keyword2", + ["isampler3D"] = "keyword2", + ["isamplerCube"] = "keyword2", + ["sampler2DMS"] = "keyword2", + ["isampler2DMS"] = "keyword2", + ["usampler2DMS"] = "keyword2", + ["sampler2DMSArray"] = "keyword2", + ["isampler2DMSArray"] = "keyword2", + ["usampler2DMSArray"] = "keyword2", + ["isampler1DArray"] = "keyword2", + ["isampler2DArray"] = "keyword2", + ["usampler1D"] = "keyword2", + ["usampler2D"] = "keyword2", + ["usampler3D"] = "keyword2", + ["usamplerCube"] = "keyword2", + ["usampler1DArray"] = "keyword2", + ["usampler2DArray"] = "keyword2", + ["sampler2DRect"] = "keyword2", + ["sampler2DRectShadow"] = "keyword2", + ["isampler2DRect"] = "keyword2", + ["usampler2DRect"] = "keyword2", + ["samplerBuffer"] = "keyword2", + ["isamplerBuffer"] = "keyword2", + ["usamplerBuffer"] = "keyword2", + + ["image1D"] = "keyword2", + ["iimage1D"] = "keyword2", + ["uimage1D"] = "keyword2", + ["image1DArray"] = "keyword2", + ["iimage1DArray"] = "keyword2", + ["uimage1DArray"] = "keyword2", + ["image2D"] = "keyword2", + ["iimage2D"] = "keyword2", + ["uimage2D"] = "keyword2", + ["image2DArray"] = "keyword2", + ["iimage2DArray"] = "keyword2", + ["uimage2DArray"] = "keyword2", + ["image2DRect"] = "keyword2", + ["iimage2DRect"] = "keyword2", + ["uimage2DRect"] = "keyword2", + ["image2DMS"] = "keyword2", + ["iimage2DMS"] = "keyword2", + ["uimage2DMS"] = "keyword2", + ["image2DMSArray"] = "keyword2", + ["iimage2DMSArray"]= "keyword2", + ["uimage2DMSArray"]= "keyword2", + ["image3D"] = "keyword2", + ["iimage3D"] = "keyword2", + ["uimage3D"] = "keyword2", + ["imageCube"] = "keyword2", + ["iimageCube"] = "keyword2", + ["uimageCube"] = "keyword2", + ["imageCubeArray"] = "keyword2", + ["iimageCubeArray"]= "keyword2", + ["uimageCubeArray"]= "keyword2", + ["imageBuffer"] = "keyword2", + ["iimageBuffer"] = "keyword2", + ["uimageBuffer"] = "keyword2", + + ["atomic_uint"] = "keyword2", + + ["radians"] = "keyword", + ["degrees"] = "keyword", + ["sin"] = "keyword", + ["cos"] = "keyword", + ["tan"] = "keyword", + ["asin"] = "keyword", + ["acos"] = "keyword", + ["atan"] = "keyword", + ["sinh"] = "keyword", + ["cosh"] = "keyword", + ["tanh"] = "keyword", + ["asinh"] = "keyword", + ["acosh"] = "keyword", + ["pow"] = "keyword", + ["exp"] = "keyword", + ["exp2"] = "keyword", + ["log2"] = "keyword", + ["sqrt"] = "keyword", + ["inversesqrt"] = "keyword", + ["abs"] = "keyword", + ["sign"] = "keyword", + ["floor"] = "keyword", + ["trunc"] = "keyword", + ["round"] = "keyword", + ["roundEven"] = "keyword", + ["ceil"] = "keyword", + ["fract"] = "keyword", + ["mod"] = "keyword", + ["modf"] = "keyword", + ["min"] = "keyword", + ["max"] = "keyword", + ["clamp"] = "keyword", + ["mix"] = "keyword", + ["step"] = "keyword", + ["smoothstep"] = "keyword", + ["isnan"] = "keyword", + ["isinf"] = "keyword", + ["floatBitsToInt"] = "keyword", + ["floatBitsToUint"] = "keyword", + ["intBitsToFloat"] = "keyword", + ["uintBitsToFloat"] = "keyword", + ["fma"] = "keyword", + ["frexp"] = "keyword", + ["ldexp"] = "keyword", + ["packUnorm2x16"] = "keyword", + ["packSnorm2x16"] = "keyword", + ["packUnorm4x8"] = "keyword", + ["packSnorm4x8"] = "keyword", + ["unpackUnorm2x16"] = "keyword", + ["unpackSnorm2x16"] = "keyword", + ["unpackUnorm4x8"] = "keyword", + ["unpackSnorm4x8"] = "keyword", + ["packHalf2x16"] = "keyword", + ["unpackHalf2x16"] = "keyword", + ["packDouble2x32"] = "keyword", + ["unpackDouble2x32"] = "keyword", + ["length"] = "keyword", + ["distance"] = "keyword", + ["dot"] = "keyword", + ["cross"] = "keyword", + ["normalize"] = "keyword", + ["ftransform"] = "keyword", + ["faceforward"] = "keyword", + ["reflect"] = "keyword", + ["refract"] = "keyword", + ["matrixCompMult"] = "keyword", + ["outerProduct"] = "keyword", + ["transpose"] = "keyword", + ["determinant"] = "keyword", + ["inverse"] = "keyword", + ["lessThan"] = "keyword", + ["lessThanEqual"] = "keyword", + ["greaterThan"] = "keyword", + ["greaterThanEqual"] = "keyword", + ["equal"] = "keyword", + ["notEqual"] = "keyword", + ["any"] = "keyword", + ["all"] = "keyword", + ["not"] = "keyword", + ["uaddCarry"] = "keyword", + ["usubBorrow"] = "keyword", + ["umulExtended"] = "keyword", + ["imulExtended"] = "keyword", + ["bitfieldExtract"] = "keyword", + ["bitfieldInsert"] = "keyword", + ["bitfieldReverse"] = "keyword", + ["bitCount"] = "keyword", + ["findLSB"] = "keyword", + ["findMSB"] = "keyword", + ["textureSize"] = "keyword", + ["textureQueryLod"] = "keyword", + ["textureQueryLevels"] = "keyword", + ["textureSamples"] = "keyword", + ["texture"] = "keyword", + ["textureProj"] = "keyword", + ["textureLod"] = "keyword", + ["textureOffset"] = "keyword", + ["texelFetch"] = "keyword", + ["texelFetchOffset"] = "keyword", + ["textureProjOffset"] = "keyword", + ["textureLodOffset"] = "keyword", + ["textureProjLod"] = "keyword", + ["textureProjLodOffset"] = "keyword", + ["textureGrad"] = "keyword", + ["textureGradOffset"] = "keyword", + ["textureProjGrad"] = "keyword", + ["textureProjGradOffset"]= "keyword", + ["textureGather"] = "keyword", + ["textureGatherOffset"] = "keyword", + ["textureGatherOffsets"] = "keyword", + + --Atomic Counter Functions + ["atomicCounterIncrement"]= "keyword", + ["atomicCounterDecrement"]= "keyword", + ["atomicCounter"] = "keyword", + ["atomicCounterAdd"] = "keyword", + ["atomicCounterSubtract"] = "keyword", + ["atomicCounterMin"] = "keyword", + ["atomicCounterMax"] = "keyword", + ["atomicCounterAnd"] = "keyword", + ["atomicCounterOr"] = "keyword", + ["atomicCounterXor"] = "keyword", + ["atomicCounterExchange"] = "keyword", + ["atomicCounterCompSwap"] = "keyword", + --Atomic Memory Functions + ["atomicAdd"] = "keyword", + ["atomicMin"] = "keyword", + ["atomicMax"] = "keyword", + ["atomicAnd"] = "keyword", + ["atomicOr"] = "keyword", + ["atomicXor"] = "keyword", + ["atomicExchange"]= "keyword", + ["atomicCompSwap"]= "keyword", + --Image Functions + ["imageSize"] = "keyword", + ["imageSamples"] = "keyword", + ["imageLoad"] = "keyword", + ["imageStore"] = "keyword", + ["imageAtomicAdd"] = "keyword", + ["imageAtomicMin"] = "keyword", + ["imageAtomicMax"] = "keyword", + ["imageAtomicAnd"] = "keyword", + ["imageAtomicOr"] = "keyword", + ["imageAtomicXor"] = "keyword", + ["imageAtomicExchange"]= "keyword", + ["imageAtomicCompSwap"]= "keyword", + --Geometry Shader Functions + ["EmitStreamVertex"] = "keyword", + ["EndStreamPrimitive"] = "keyword", + ["EmitVertex"] = "keyword", + ["EndPrimitive"] = "keyword", + --Fragment Processing Functions + ["dFdx"] = "keyword", + ["dFdy"] = "keyword", + ["dFdxFine"] = "keyword", + ["dFdyFine"] = "keyword", + ["dFdxCoarse"] = "keyword", + ["dFdyCoarse"] = "keyword", + ["fwidth"] = "keyword", + ["fwidthFine"] = "keyword", + ["fwidthCoarse"] = "keyword", + ["interpolateAtCentroid"]= "keyword", + ["interpolateAtSample"] = "keyword", + ["interpolateAtOffset"] = "keyword", + --Shader Invocation Control Functions + ["barrier"] = "keyword", + --Shader Memory Control Functions + ["memoryBarrier"] = "keyword", + ["memoryBarrierAtomicCounter"]= "keyword", + ["memoryBarrierBuffer"] = "keyword", + ["memoryBarrierShared"] = "keyword", + ["memoryBarrierImage"] = "keyword", + ["groupMemoryBarrier"] = "keyword", + --Subpass-Input Functions + ["subpassLoad"] = "keyword", + --Shader Invocation Group Functions + ["anyInvocation"] = "keyword", + ["allInvocations"] = "keyword", + ["allInvocationsEqual"]= "keyword", + + --"In addition, when targeting Vulkan, the following keywords also exist:" + ["texture1D"] = "keyword", + ["texture1DArray"] = "keyword", + ["itexture1D"] = "keyword", + ["itexture1DArray"] = "keyword", + ["utexture1D"] = "keyword", + ["utexture1DArray"] = "keyword", + ["texture2D"] = "keyword", + ["texture2DArray"] = "keyword", + ["itexture2D"] = "keyword", + ["itexture2DArray"] = "keyword", + ["utexture2D"] = "keyword", + ["utexture2DArray"] = "keyword", + ["texture2DRect"] = "keyword", + ["itexture2DRect"] = "keyword", + ["utexture2DRect"] = "keyword", + ["texture2DMS"] = "keyword", + ["itexture2DMS"] = "keyword", + ["utexture2DMS"] = "keyword", + ["texture2DMSArray"] = "keyword", + ["itexture2DMSArray"]= "keyword", + ["utexture2DMSArray"]= "keyword", + ["texture3D"] = "keyword", + ["itexture3D"] = "keyword", + ["utexture3D"] = "keyword", + ["textureCube"] = "keyword", + ["itextureCube"] = "keyword", + ["utextureCube"] = "keyword", + ["textureCubeArray"] = "keyword", + ["itextureCubeArray"]= "keyword", + ["utextureCubeArray"]= "keyword", + ["textureBuffer"] = "keyword", + ["itextureBuffer"] = "keyword", + ["utextureBuffer"] = "keyword", + ["sampler"] = "keyword2", + ["samplerShadow"] = "keyword2", + ["subpassInput"] = "keyword2", + ["isubpassInput"] = "keyword2", + ["usubpassInput"] = "keyword2", + ["subpassInputMS"] = "keyword2", + ["isubpassInputMS"] = "keyword2", + ["usubpassInputMS"] = "keyword2", + }, +} + diff --git a/debian/extra/plugins/language_gmi.lua b/debian/extra/plugins/language_gmi.lua new file mode 100644 index 0000000..c5d819a --- /dev/null +++ b/debian/extra/plugins/language_gmi.lua @@ -0,0 +1,21 @@ +-- mod-version:3 +local syntax = require "core.syntax" + + + +syntax.add { + name = "Gemtext", + files = { "%.gmi$" }, + patterns = { + { pattern = { "```", "```" }, type = "string" }, + { pattern = "#.*", type = "keyword" }, + { pattern = "%*%s", type = "keyword2" }, + { pattern = "=>", type = "function" }, + { pattern = "https?://%S+", type = "literal" }, + { pattern = "gemini?://%S+", type = "literal" }, + { pattern = ">.*", type = "comment" }, + { pattern = ".*[>*#]", type = "normal" }, + { pattern = ".*=>", type = "normal" } + }, + symbols = { }, +} diff --git a/debian/extra/plugins/language_go.lua b/debian/extra/plugins/language_go.lua new file mode 100644 index 0000000..03b93d6 --- /dev/null +++ b/debian/extra/plugins/language_go.lua @@ -0,0 +1,232 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Go", + files = { "%.go$" }, + comment = "//", + block_comment = {"/*", "*/"}, + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "`", "`", '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "0[oO_][0-7]+i?", type = "number" }, + { pattern = "-?0x[%x_]+i?", type = "number" }, + { pattern = "-?%d+_%di?", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?i?", type = "number" }, + { pattern = "-?%.?%d+f?i?", type = "number" }, + -- goto label + { pattern = "^%s+()[%a_][%w%_]*()%s*:%s$", -- this is to fix `default:` + type = { "normal", "function", "normal" } + }, + { pattern = "^%s*[%a_][%w%_]*()%s*:%s$", + type = { "function", "normal" } + }, + -- pointer, generic and reference type + { pattern = "[%*~&]()[%a_][%w%_]*", + type = { "operator", "keyword2" } + }, + -- slice type + { pattern = "%[%]()[%a_][%w%_]*", + type = { "operator", "keyword2" } + }, + -- type coerce + { + pattern = "%.%(()[%a_][%w_]*()%)", + type = { "normal", "keyword2", "normal" } + }, + -- struct literal + { pattern = "[%a_][%w%_]*()%s*{%s*", + type = { "keyword2", "normal" } + }, + -- operators + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = ":=", type = "operator" }, + -- function calls + { pattern = "func()%s*[%a_][%w_]*()%f[%[(]", -- function statement + type = {"keyword", "function", "normal"} + }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "%.()[%a_][%w_]*%f[(]", + type = { "normal", "function" } + }, + -- type declaration + { pattern = "type()%s+()[%a_][%w%_]*", + type = { "keyword", "normal", "keyword2" } + }, + -- variable declaration + { pattern = "var()%s+()[%a_][%w%_]*", + type = { "keyword", "normal", "symbol" } + }, + -- goto + { pattern = "goto()%s+()[%a_][%w%_]*", + type = { "keyword", "normal", "function" } + }, + -- if fix + { pattern = "if()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- for fix + { pattern = "for()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- return fix + { pattern = "return()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- range fix + { pattern = "range()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- func fix + { pattern = "func()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- switch fix + { pattern = "switch()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- case fix + { pattern = "case()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- break fix + { pattern = "break()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- continue fix + { pattern = "continue()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- package fix + { pattern = "package()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- go fix + { pattern = "go()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- chan fix + { pattern = "chan()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- defer fix + { pattern = "defer()%s+%f[%a_]", + type = { "keyword", "normal" } + }, + -- field declaration + { pattern = "[%a_][%w%_]*()%s*():%s*%f[%w%p]", + type = { "function", "normal", "operator" } + }, + -- parameters or declarations + { pattern = "[%a_][%w%_]*()%s+()[%*~&]?()[%a_][%w%_]*", + type = { "literal", "normal", "operator", "keyword2" } + }, + { pattern = "[%a_][%w_]*()%s+()%[%]()[%a_][%w%_]*", + type = { "literal", "normal", "normal", "keyword2" } + }, + -- single return type + { + pattern = "%)%s+%(?()[%a_][%w%_]*()%)?%s+%{", + type = { "normal", "keyword2", "normal" } + }, + -- sub fields + { pattern = "%.()[%a_][%w_]*", + type = { "normal", "literal" } + }, + -- every other symbol + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["if"] = "keyword", + ["else"] = "keyword", + ["elseif"] = "keyword", + ["for"] = "keyword", + ["continue"] = "keyword", + ["return"] = "keyword", + ["struct"] = "keyword", + ["switch"] = "keyword", + ["case"] = "keyword", + ["default"] = "keyword", + ["const"] = "keyword", + ["package"] = "keyword", + ["import"] = "keyword", + ["func"] = "keyword", + ["var"] = "keyword", + ["type"] = "keyword", + ["interface"] = "keyword", + ["select"] = "keyword", + ["break"] = "keyword", + ["range"] = "keyword", + ["chan"] = "keyword", + ["defer"] = "keyword", + ["go"] = "keyword", + ["fallthrough"] = "keyword", + ["goto"] = "keyword", + ["iota"] = "keyword2", + ["int"] = "keyword2", + ["int64"] = "keyword2", + ["int32"] = "keyword2", + ["int16"] = "keyword2", + ["int8"] = "keyword2", + ["uint"] = "keyword2", + ["uint64"] = "keyword2", + ["uint32"] = "keyword2", + ["uint16"] = "keyword2", + ["uint8"] = "keyword2", + ["uintptr"] = "keyword2", + ["float64"] = "keyword2", + ["float32"] = "keyword2", + ["map"] = "keyword2", + ["string"] = "keyword2", + ["rune"] = "keyword2", + ["bool"] = "keyword2", + ["byte"] = "keyword2", + ["error"] = "keyword2", + ["complex64"] = "keyword2", + ["complex128"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + ["nil"] = "literal", + }, +} + +syntax.add { + name = "Go", + files = { PATHSEP .. "go%.mod" }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment"}, + { pattern = "module() %S+()", + type = { "keyword", "string", "normal"} + }, + { pattern = "go() %S+()", + type = { "keyword", "string", "normal" } + }, + { pattern = "%S+() v%S+()", + type = { "string", "keyword", "normal" } + }, + }, + symbols = { + ["require"] = "keyword", + ["module"] = "keyword", + ["go"] = "keyword", + } +} + +syntax.add { + name = "Go", + files = { PATHSEP .. "go%.sum" }, + patterns = { + { pattern = "%S+() v[^/]-() h1:()%S+()=", + type = { "string", "keyword", "normal", "string", "normal" } + }, + { pattern = "%S+() v[^/]-()/%S+() h1:()%S+()=", + type = { "string", "keyword", "string", "normal", "string", "normal" } + }, + }, + symbols = {} +} + diff --git a/debian/extra/plugins/language_graphql.lua b/debian/extra/plugins/language_graphql.lua new file mode 100644 index 0000000..7627ee2 --- /dev/null +++ b/debian/extra/plugins/language_graphql.lua @@ -0,0 +1,42 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "GraphQL", + files = { "%.graphql$", "%.gql$" }, + comment = "#", + block_comment = { '"""', '"""' }, + patterns = { + { pattern = { '"""', '"""' }, type = "comment" }, + { pattern = "#.*", type = "comment" }, + { pattern = { '"', '"', "\\" }, type = "string" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "%s*[@]%s*[%a_][%w_]*", type = "function" }, + { pattern = "!", type = "operator" }, + { pattern = "%s*=%s*", type = "operator" }, + { pattern = "%s*%$[%a_][%w_]*:*", type = "literal" }, + { pattern = "query%s*()[%a_][%w_]*[(]", type = { "keyword", "function" } }, + { pattern = "mutation%s*()[%a_][%w_]*[(]", type = { "keyword", "function" } }, + { pattern = ":%s*%[*()[%a_,%s][%w_,%s]*()%]*()[!]*", type = { "symbol", "literal", "symbol", "operator" } }, + }, + symbols = { + ["query"] = "keyword", + ["mutation"] = "keyword", + ["type"] = "keyword", + ["interface"] = "keyword", + ["input"] = "keyword", + ["fragment"] = "keyword", + ["directive"] = "keyword", + ["extends"] = "keyword", + ["implements"] = "keyword", + ["on"] = "keyword", + ["enum"] = "keyword", + ["scalar"] = "keyword", + ["union"] = "keyword", + ["schema"] = "keyword", + ["extend"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + }, +} + diff --git a/debian/extra/plugins/language_gravity.lua b/debian/extra/plugins/language_gravity.lua new file mode 100644 index 0000000..d5bd761 --- /dev/null +++ b/debian/extra/plugins/language_gravity.lua @@ -0,0 +1,98 @@ +-- mod-version:3 +local syntax = require 'core.syntax' + +syntax.add { + name = "Gravity", + files = { "%.gravity$" }, + comment = "//", + block_comment = {"/*", "*/"}, + patterns = { + { pattern = "#![^\n]+", type = "comment" }, + { pattern = "//[^\n]+", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', "\\" }, type = "string" }, + + { pattern = "[~=!<>]=?", type = "operator" }, + { pattern = "[!=]==", type = "operator" }, + { pattern = "[%+%-%*/%%&|^]", type = "operator" }, + { pattern = "%.%.[%.<]", type = "operator" }, + + { pattern = "0[bB][0-1]+%f[%D]", type = "number" }, + { pattern = "0[oO][0-7]+", type = "number" }, + { pattern = "0[xX]%x+", type = "number" }, + { pattern = "%.?%d+[eE]?%-?%d*", type = "number" }, + + { pattern = "#%s*include%s*%f[\"]", type = "literal"}, + { pattern = "#%s*unittest%s*%f[{]", type = "literal"}, + + --{ pattern = "[%+%-%*/]%s*()%(", type = { "function", "normal" }}, + { pattern = "[%a_][%w_]+%s*%f[%(]", type = "function"}, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + ["self"] = "keyword2", + + ["Object"] = "literal", + ["Int"] = "literal", + ["Float"] = "literal", + ["String"] = "literal", + ["Bool"] = "literal", + ["Null"] = "literal", + ["Class"] = "literal", + ["Function"] = "literal", + ["Fiber"] = "literal", + ["Instance"] = "literal", + ["List"] = "literal", + ["Map"] = "literal", + ["Range"] = "literal", + + ["System"] = "literal", + ["Math"] = "literal", + ["File"] = "literal", + ["ENV"] = "literal", + + ["if"] = "keyword", + ["in"] = "keyword", + ["or"] = "keyword", + ["is"] = "operator", + ["for"] = "keyword", + ["var"] = "keyword", + ["and"] = "keyword", + ["not"] = "keyword", + ["func"] = "keyword", + ["else"] = "keyword", + ["true"] = "keyword", + ["enum"] = "keyword", + ["case"] = "keyword", + ["null"] = "keyword", + ["file"] = "keyword", + ["lazy"] = "keyword", + ["super"] = "keyword", + ["break"] = "keyword", + ["while"] = "keyword", + ["class"] = "keyword", + ["const"] = "keyword", + ["event"] = "keyword", + ["_func"] = "keyword", + ["_args"] = "keyword", + ["struct"] = "keyword", + ["repeat"] = "keyword", + ["switch"] = "keyword", + ["return"] = "keyword", + ["public"] = "keyword", + ["static"] = "keyword", + ["extern"] = "keyword", + ["import"] = "keyword", + ["module"] = "keyword", + ["default"] = "keyword", + ["private"] = "keyword", + ["continue"] = "keyword", + ["internal"] = "keyword", + ["undefined"] = "keyword", + } +} + + diff --git a/debian/extra/plugins/language_groovy.lua b/debian/extra/plugins/language_groovy.lua new file mode 100644 index 0000000..c9d3a62 --- /dev/null +++ b/debian/extra/plugins/language_groovy.lua @@ -0,0 +1,109 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Groovy", + files = { "%.groovy$", PATHSEP .. "Jenkinsfile$" }, + comment = "//", + block_comment = { "/*", "*/" }, + patterns = { + { pattern = "//.*", type = "comment" }, -- Single-line comment + { pattern = { "/%*", "%*/" }, type = "comment" }, -- Multi-line comment + { pattern = { '"', '"', '\\' }, type = "string" }, -- String, double quotes + { pattern = { "'", "'", '\\' }, type = "string" }, -- String, apices + { pattern = { "%/", "%/", '\\' }, type = "string" }, -- Slashy string + { pattern = { "%$%/", "%/%$", '\\' }, type = "string" }, -- Dollar slashy string + { pattern = "'\\x%x?%x?%x?%x'", type = "string" }, -- character hexadecimal escape sequence + { pattern = "'\\u%x%x%x%x'", type = "string" }, -- character unicode escape sequence + { pattern = "'\\?.'", type = "string" }, -- character literal + { pattern = "-?0x%x+", type = "number" }, -- ? + { pattern = "-?%d+[%d%.eE]*[a-zA-Z]?", type = "number" }, -- ? + { pattern = "-?%.?%d+", type = "number" }, -- ? + { pattern = "-?[%d_+]+[a-zA-Z]?", type = "number" }, -- ? + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, -- Operators + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- Function/Class/Method/... + { pattern = "[%a_][%w_]*%f[%[]", type = "function" }, -- Custom Type + { regex = "[A-Z]+_?[A-Z]+", type = "keyword2" }, -- Constants + { pattern = "import()%s+()[%w_.]+", type = { "keyword", "normal", "normal" } }, + { pattern = "[%a_][%w_]*", type = "symbol" }, -- ? + { pattern = "[a-zA-Z]+%.+", type = "function" }, -- Lib path + -- TODO: .class. + }, + symbols = { + -- Reserved keywords + ["abstract"] = "keyword", + ["assert"] = "keyword", + ["break"] = "keyword", + ["case"] = "keyword", + ["catch"] = "keyword", + ["class"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["def"] = "keyword", + ["default"] = "keyword", + ["do"] = "keyword", + ["else"] = "keyword", + ["enum"] = "keyword", + ["extends"] = "keyword", + ["final"] = "keyword", + ["finally"] = "keyword", + ["for"] = "keyword", + ["goto"] = "keyword", + ["if"] = "keyword", + ["implements"] = "keyword", + ["import"] = "keyword", + ["instanceof"] = "keyword", + ["interface"] = "keyword", + ["native"] = "keyword", + ["new"] = "keyword", + ["non-sealed"] = "keyword", + ["package"] = "keyword", + ["public"] = "keyword", + ["protected"] = "keyword", + ["private"] = "keyword", + ["return"] = "keyword", + ["static"] = "keyword", + ["strictfp"] = "keyword", + ["super"] = "keyword", + ["switch"] = "keyword", + ["synchronizedthis"] = "keyword", + ["threadsafe"] = "keyword", + ["throw"] = "keyword", + ["throws"] = "keyword", + ["transient"] = "keyword", + ["try"] = "keyword", + ["while"] = "keyword", + + -- Contextual keywords + ["as"] = "keyword", + ["in"] = "keyword", + ["permitsrecord"] = "keyword", + ["sealed"] = "keyword", + ["trait"] = "keyword", + ["var"] = "keyword", + ["yields"] = "keyword", + + -- ? + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + ["boolean"] = "literal", + + -- Types + ["char"] = "keyword", + ["byte"] = "keyword", + ["short"] = "keyword", + ["int"] = "keyword", + ["long"] = "keyword", + ["float"] = "keyword", + ["double"] = "keyword", + + ["Integer"] = "keyword", + ["BigInteger"] = "keyword", + ["Long"] = "keyword", + ["Float"] = "keyword", + ["BigDecimal"] = "keyword", + ["Double"] = "keyword", + ["String"] = "keyword", + }, +} diff --git a/debian/extra/plugins/language_hare.lua b/debian/extra/plugins/language_hare.lua new file mode 100644 index 0000000..fba4f44 --- /dev/null +++ b/debian/extra/plugins/language_hare.lua @@ -0,0 +1,91 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Hare", + files = { "%.ha$" }, + comment = "//", + patterns = { + { pattern = "//.*", type = "comment" }, + -- { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "^@", type = "keyword" }, + }, + symbols = { + ["export"] = "keyword", + ["fn"] = "keyword", + ["use"] = "keyword", + ["const"] = "keyword", + ["let"] = "keyword", + ["defer"] = "keyword", + ["static"] = "keyword", + ["yield"] = "keyword", + ["case"] = "keyword", + ["match"] = "keyword", + ["return"] = "keyword", + ["switch"] = "keyword", + ["for"] = "keyword", + ["if"] = "keyword", + ["type"] = "keyword", + ["abort"] = "keyword", + ["align"] = "keyword", + ["alloc"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["def"] = "keyword", + ["delete"] = "keyword", + ["else"] = "keyword", + ["free"] = "keyword", + ["insert"] = "keyword", + ["is"] = "keyword", + ["len"] = "keyword", + ["offset"] = "keyword", + ["vaarg"] = "keyword", + ["vaend"] = "keyword", + ["vastart"] = "keyword", + ["fini"] = "keyword", + ["init"] = "keyword", + ["test"] = "keyword", + + ["nullable"] = "keyword2", + ["str"] = "keyword2", + ["void"] = "keyword2", + ["int"] = "keyword2", + ["uint"] = "keyword2", + ["struct"] = "keyword2", + ["union"] = "keyword2", + ["enum"] = "keyword2", + ["u8"] = "keyword2", + ["u16"] = "keyword2", + ["u32"] = "keyword2", + ["u64"] = "keyword2", + ["i8"] = "keyword2", + ["i16"] = "keyword2", + ["i32"] = "keyword2", + ["i64"] = "keyword2", + ["f32"] = "keyword2", + ["f64"] = "keyword2", + ["size"] = "keyword2", + ["rune"] = "keyword2", + ["bool"] = "keyword2", + ["valist"] = "keyword2", + ["uintptr"] = "keyword2", + ["rconst"] = "keyword2", + ["fconst"] = "keyword2", + ["iconst"] = "keyword2", + + ["fmt"] = "literal", + ["true"] = "literal", + ["false"] = "literal", + ["signed"] = "literal", + ["unsigned"] = "literal", + ["null"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_haxe.lua b/debian/extra/plugins/language_haxe.lua new file mode 100644 index 0000000..0289d8d --- /dev/null +++ b/debian/extra/plugins/language_haxe.lua @@ -0,0 +1,113 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Haxe Compiler Arguments", + files = "%.hxml$", + comment = "#", + patterns = { + { pattern = "#.*", type = "comment"}, + { pattern = "%-[%-%w_]*", type="keyword"}, + { pattern = "%.()%u[%w_]*", type = {"normal", "keyword2"}}, + }, + symbols = {} +} + +syntax.add { + name = "Haxe String Interpolation", + files = "%.hx__string_interp$", + patterns = { + { pattern = {"%${", "}", "\\"}, type="keyword", syntax = ".hx" }, + { pattern = {"%$", "%s", "\\"}, type="keyword", syntax = ".hx" }, + { pattern = "[^ ]", type = "string"} + }, + symbols = {} +} + +syntax.add { + name = "Haxe Regular Expressions", + files = "%.hx__regex$", + patterns = { + { pattern = "[%[%]%(%)]", type = "string" }, + { pattern = "[%.%*%+%?%^%$%|%-]", type = "operator" }, + }, + symbols = {} +} + +syntax.add { + name = "Haxe", + files = "%.hx$", + comment = "//", + patterns = { + { pattern = {"%~%/", "%/[igmsu]*"}, type = "keyword2", syntax = ".hx__regex" }, + { pattern = "%.%.%.", type = "operator" }, + { pattern = "%<()%u[%w_]*()%>*", type = {"operator", "keyword2", "operator"}}, + { pattern = "%#%s*[%a_]*().*\n", type = {"keyword", "normal"} }, + { pattern = "import%s+()%u[%w]*", type = {"keyword", "keyword2"}}, + { pattern = "import%s+()[%w%.]*%.()%u[%w]*", type = {"keyword", "normal", "keyword2"}}, + { pattern = "abstract%s+()%u[%w_]*%s*%(()%s*%u[%w_]*", type = {"keyword2", "normal", "keyword2"} }, + { pattern = "from%s+()%u[%w_]*%s+()to%s+()%u[%w_]*", type = {"keyword", "keyword2", "keyword", "keyword2"}}, + { pattern = "//.*\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", "\\" }, type = "string", syntax = ".hx__string_interp"}, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+%.[%deE]+", type = "number" }, + { pattern = "-?%d+[%deE]+", type = "number" }, + { pattern = "[%+%-%.=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "[%a_][%w_]*()%s*%f[(]", type = {"function", "normal"} }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = ":()%u[%a_][%w_]*", type = {"normal", "keyword2"}}, + { pattern = "@:[%a_][%w_]*%f[(]", type = "keyword" }, + { pattern = "%$type", type = "keyword" }, + }, + symbols = { + ["abstract"] = "keyword2", + ["extends"] = "keyword2", + ["typedef"] = "keyword2", + ["implements"] = "keyword2", + ["import"] = "keyword", + ["package"] = "keyword", + ["using"] = "keyword2", + ["macro"] = "keyword2", + ["class"] = "keyword", + ["function"] = "keyword2", + ["var"] = "keyword2", + ["extern"] = "keyword2", + ["in"] = "keyword", + ["cast"] = "keyword", + ["get"] = "keyword", + ["set"] = "keyword", + ["never"] = "keyword", + ["inline"] = "keyword", + ["trace"] = "keyword", + ["final"] = "keyword", + ["break"] = "keyword", + ["case"] = "keyword", + ["catch"] = "keyword", + ["continue"] = "keyword", + ["default"] = "keyword", + ["do"] = "keyword", + ["else"] = "keyword", + ["enum"] = "keyword", + ["for"] = "keyword", + ["if"] = "keyword", + ["interface"] = "keyword", + ["new"] = "keyword", + ["override"] = "keyword", + ["private"] = "keyword", + ["public"] = "keyword", + ["return"] = "keyword", + ["static"] = "keyword", + ["switch"] = "keyword", + ["this"] = "keyword", + ["throw"] = "keyword", + ["try"] = "keyword", + ["while"] = "keyword", + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + }, +} + diff --git a/debian/extra/plugins/language_hlsl.lua b/debian/extra/plugins/language_hlsl.lua new file mode 100644 index 0000000..e1d5570 --- /dev/null +++ b/debian/extra/plugins/language_hlsl.lua @@ -0,0 +1,277 @@ +-- mod-version:3 + +local style = require "core.style" +local common = require "core.common" + +local syntax = require "core.syntax" + +syntax.add { + name = "HLSL", + files = { "%.hlsl$", }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { "#", "[^\\]\n" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + + { pattern = "int[1-9]x[1-9]", type = "keyword2" }, + { pattern = "int1[0-6]x[1-9]", type = "keyword2" }, + { pattern = "int[1-9]x1[0-6]", type = "keyword2" }, + { pattern = "int1[0-6]x1[0-6]", type = "keyword2" }, + { pattern = "int[1-4]", type = "keyword2" }, + + { pattern = "uint[1-9]x[1-9]", type = "keyword2" }, + { pattern = "uint1[0-6]x[1-9]", type = "keyword2" }, + { pattern = "uint[1-9]x1[0-6]", type = "keyword2" }, + { pattern = "uint1[0-6]x1[0-6]", type = "keyword2" }, + { pattern = "uint[1-4]", type = "keyword2" }, + + { pattern = "dword[1-9]x[1-9]", type = "keyword2" }, + { pattern = "dword1[0-6]x[1-9]", type = "keyword2" }, + { pattern = "dword[1-9]x1[0-6]", type = "keyword2" }, + { pattern = "dword1[0-6]x1[0-6]", type = "keyword2" }, + { pattern = "dword[1-4]", type = "keyword2" }, + + { pattern = "half[1-9]x[1-9]", type = "keyword2" }, + { pattern = "half1[0-6]x[1-9]", type = "keyword2" }, + { pattern = "half[1-9]x1[0-6]", type = "keyword2" }, + { pattern = "half1[0-6]x1[0-6]", type = "keyword2" }, + { pattern = "half[1-4]", type = "keyword2" }, + + { pattern = "float[1-9]x[1-9]", type = "keyword2" }, + { pattern = "float1[0-6]x[1-9]", type = "keyword2" }, + { pattern = "float[1-9]x1[0-6]", type = "keyword2" }, + { pattern = "float1[0-6]x1[0-6]", type = "keyword2" }, + { pattern = "float[1-4]", type = "keyword2" }, + + { pattern = "double[1-9]x[1-9]", type = "keyword2" }, + { pattern = "double1[0-6]x[1-9]", type = "keyword2" }, + { pattern = "double[1-9]x1[0-6]", type = "keyword2" }, + { pattern = "double1[0-6]x1[0-6]", type = "keyword2" }, + { pattern = "double[1-4]", type = "keyword2" }, + + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + --https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-keywords + --The symbols are added in the order they appear on this webpage, which is alphabetically + ["AppendStructuredBuffer"]= "keyword", + ["asm"] = "keyword", + ["asm_fragment"] = "keyword", + ["BlendState"] = "keyword2", + ["bool"] = "keyword2", + ["break"] = "keyword", + ["Buffer"] = "keyword2", + ["ByteAddressBuffer"]= "keyword2", + ["case"] = "keyword", + ["cbuffer"] = "keyword2", + ["centroid"] = "keyword2", + ["class"] = "keyword", + ["column_major"] = "keyword", + ["compile"] = "keyword", + ["compile_fragment"] = "keyword", + ["CompileShader"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["ComputeShader"] = "keyword", + ["ConsumeStructuredBuffer"]= "keyword", + ["default"] = "keyword", + ["DepthStencilState"]= "keyword", + ["DepthStencilView"] = "keyword", + ["discard"] = "keyword", + ["do"] = "keyword", + ["double"] = "keyword2", + ["DomainShader"] = "keyword2", + ["dword"] = "keyword2", + ["else"] = "keyword", + ["export"] = "keyword", + ["extern"] = "keyword", + ["false"] = "literal", + ["float"] = "keyword2", + ["for"] = "keyword", + ["fxgroup"] = "keyword2", + ["GeometryShader"] = "keyword2", + ["groupshared"] = "keyword", + ["half"] = "keyword2", + ["HullShader"] = "keyword2", + ["if"] = "keyword", + ["in"] = "keyword", + ["inline"] = "keyword", + ["inout"] = "keyword", + ["InputPatch"] = "keyword2", + ["int"] = "keyword2", + ["interface"] = "keyword", + ["line"] = "keyword2", + ["lineadj"] = "keyword2", + ["linear"] = "keyword", + ["LineStream"] = "keyword2", + ["matrix"] = "keyword2", + ["min16float"] = "keyword2", + ["min10float"] = "keyword2", + ["min16int"] = "keyword2", + ["min12int"] = "keyword2", + ["min16uint"] = "keyword2", + ["namespace"] = "keyword", + ["nointerpolation"] = "keyword", + ["noperspective"] = "keyword", + ["NULL"] = "literal", + ["out"] = "keyword", + ["OutputPatch"] = "keyword2", + ["packoffset"] = "keyword", + ["pass"] = "keyword", + ["pixelfragment"] = "keyword", + ["PixelShader"] = "keyword2", + ["point"] = "keyword2", + ["PointStream"] = "keyword2", + ["precise"] = "keyword", + ["RasterizerState"] = "keyword2", + ["RenderTargetView"] = "keyword2", + ["return"] = "keyword", + ["register"] = "keyword", + ["row_major"] = "keyword", + ["RWBuffer"] = "keyword2", + ["RWByteAddressBuffer"]= "keyword2", + ["RWStructuredBuffer"]= "keyword2", + ["RWTexture1D"] = "keyword2", + ["RWTexture1DArray"] = "keyword2", + ["RWTexture2D"] = "keyword2", + ["RWTexture2DArray"] = "keyword2", + ["RWTexture3D"] = "keyword2", + ["sample"] = "keyword", + ["sampler"] = "keyword2", + ["SamplerState"] = "keyword2", + ["SamplerComparisonState"]= "keyword2", + ["shared"] = "keyword", + ["snorm"] = "keyword", + ["stateblock"] = "keyword", + ["stateblock_state"] = "keyword", + ["static"] = "keyword", + ["string"] = "keyword2", + ["struct"] = "keyword", + ["switch"] = "keyword", + ["StructuredBuffer"] = "keyword2", + ["tbuffer"] = "keyword2", + ["technique"] = "keyword2", + ["technique10"] = "keyword2", + ["technique11"] = "keyword2", + ["texture"] = "keyword2", + ["Texture1D"] = "keyword2", + ["Texture1DArray"] = "keyword2", + ["Texture2D"] = "keyword2", + ["Texture2DArray"] = "keyword2", + ["Texture2DMS"] = "keyword2", + ["Texture2DMSArray"] = "keyword2", + ["Texture3D"] = "keyword2", + ["TextureCube"] = "keyword2", + ["TextureCubeArray"] = "keyword2", + ["true"] = "literal", + ["typedef"] = "keyword", + ["triangle"] = "keyword2", + ["triangleadj"] = "keyword2", + ["TriangleStream"] = "keyword2", + ["uint"] = "keyword2", + ["uniform"] = "keyword", + ["unorm"] = "keyword", + ["unsigned"] = "keyword", + ["vector"] = "keyword2", + ["vertexfragment"] = "keyword2", + ["VertexShader"] = "keyword2", + ["void"] = "keyword", + ["volatile"] = "keyword", + ["while"] = "keyword", + + --https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-intrinsic-functions + --The symbols are added in the order they appear on this webpage, which is alphabetically + ["abort"] = "keyword", + ["abs"] = "keyword", + ["acos"] = "keyword", + ["all"] = "keyword", + ["any"] = "keyword", + ["asdouble"] = "keyword", + ["asfloat"] = "keyword", + ["asin"] = "keyword", + ["asint"] = "keyword", + ["asuint"] = "keyword", + ["atan"] = "keyword", + ["atan2"] = "keyword", + ["ceil"] = "keyword", + ["clamp"] = "keyword", + ["clip"] = "keyword", + ["cos"] = "keyword", + ["cosh"] = "keyword", + ["countbits"] = "keyword", + ["cross"] = "keyword", + ["ddx"] = "keyword", + ["ddx_coarse"] = "keyword", + ["ddx_fine"] = "keyword", + ["ddy"] = "keyword", + ["ddy_coarse"] = "keyword", + ["ddy_fine"] = "keyword", + ["degrees"] = "keyword", + ["determinant"] = "keyword", + ["distance"] = "keyword", + ["dot"] = "keyword", + ["dst"] = "keyword", + ["errorf"] = "keyword", + ["exp"] = "keyword", + ["exp2"] = "keyword", + ["f16tof32"] = "keyword", + ["f32tof16"] = "keyword", + ["faceforward"] = "keyword", + ["firstbithigh"]= "keyword", + ["firstbitlow"] = "keyword", + ["floor"] = "keyword", + ["fma"] = "keyword", + ["fmod"] = "keyword", + ["frac"] = "keyword", + ["frexp"] = "keyword", + ["fwidth"] = "keyword", + ["isfinite"] = "keyword", + ["isinf"] = "keyword", + ["isnan"] = "keyword", + ["ldexp"] = "keyword", + ["length"] = "keyword", + ["lerp"] = "keyword", + ["lit"] = "keyword", + ["log"] = "keyword", + ["log10"] = "keyword", + ["log2"] = "keyword", + ["mad"] = "keyword", + ["max"] = "keyword", + ["min"] = "keyword", + ["modf"] = "keyword", + ["msad4"] = "keyword", + ["mul"] = "keyword", + ["noise"] = "keyword", + ["normalize"] = "keyword", + ["pow"] = "keyword", + ["printf"] = "keyword", + ["radians"] = "keyword", + ["rcp"] = "keyword", + ["reflect"] = "keyword", + ["refract"] = "keyword", + ["reversebits"] = "keyword", + ["round"] = "keyword", + ["rsqrt"] = "keyword", + ["saturate"] = "keyword", + ["sign"] = "keyword", + ["sin"] = "keyword", + ["sincos"] = "keyword", + ["sinh"] = "keyword", + ["smoothstep"] = "keyword", + ["sqrt"] = "keyword", + ["step"] = "keyword", + ["tan"] = "keyword", + ["tanh"] = "keyword", + ["transpose"] = "keyword", + ["trunc"] = "keyword", + }, +} + diff --git a/debian/extra/plugins/language_hs.lua b/debian/extra/plugins/language_hs.lua new file mode 100644 index 0000000..39dbc7a --- /dev/null +++ b/debian/extra/plugins/language_hs.lua @@ -0,0 +1,48 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Haskell", + files = { "%.hs$" }, + comment = "--", + block_comment = {"{-", "-}"}, + patterns = { + { pattern = "%-%-.*", type = "comment" }, + { pattern = { "{%-", "%-}" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[!%#%$%%&*+./%<=>%?@\\%^|%-~:]", type = "operator" }, + { pattern = "[%a_'][%w_']*", type = "symbol" }, + }, + symbols = { + ["as"] = "keyword", + ["case"] = "keyword", + ["of"] = "keyword", + ["class"] = "keyword", + ["data"] = "keyword", + ["default"] = "keyword", + ["deriving"] = "keyword", + ["do"] = "keyword", + ["forall"] = "keyword", + ["foreign"] = "keyword", + ["hiding"] = "keyword", + ["if"] = "keyword", + ["then"] = "keyword", + ["else"] = "keyword", + ["import"] = "keyword", + ["infix"] = "keyword", + ["infixl"] = "keyword", + ["infixr"] = "keyword", + ["let"] = "keyword", + ["in"] = "keyword", + ["mdo"] = "keyword", + ["module"] = "keyword", + ["newtype"] = "keyword", + ["qualified"] = "keyword", + ["type"] = "keyword", + ["where"] = "keyword", + }, +} diff --git a/debian/extra/plugins/language_htaccess.lua b/debian/extra/plugins/language_htaccess.lua new file mode 100644 index 0000000..8c2909e --- /dev/null +++ b/debian/extra/plugins/language_htaccess.lua @@ -0,0 +1,212 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +local keywords = { + "AcceptFilter", "AcceptMutex", "AcceptPathInfo", "AccessFileName", "Action", "AddAlt", + "AddAltByEncoding", "AddAltByType", "AddCharset", "AddDefaultCharset", "AddDescription", + "AddEncoding", "AddHandler", "AddIcon", "AddIconByType", "AddIconByEncoding", "AddIconByEncoding", + "AddIconByType", "AddInputFilter", "AddLanguage", "AddModuleInfo", "AddOutputFilterByType", + "AddOutputFilter", "AddOutputFilterByType", "AddType", "Alias", "ScriptAlias", "ServerAlias", + "AliasMatch", "Allow", "AllowOverride", "AllowEncodedSlashes", "_ROUTING__allow_GET", + "_ROUTING__allow_HEAD", "_ROUTING__allow_POST", "Allow", "AllowOverride", "AllowEncodedSlashes", + "AllowCONNECT", "AllowEncodedSlashes", "AllowMethods", "AllowOverride", "AllowOverrideList", + "Anonymous", "Anonymous_LogEmail", "Anonymous_NoUserID", "Anonymous_Authoritative", + "Anonymous_LogEmail", "Anonymous_MustGiveEmail", "Anonymous_NoUserId", "Anonymous_VerifyEmail", + "AssignUserID", "AsyncRequestWorkerFactor", "AuthAuthoritative", "AuthBasicAuthoritative", + "AuthBasicFake", "AuthBasicProvider", "AuthBasicUseDigestAlgorithm", "AuthDBDUserPWQuery", + "AuthDBDUserRealmQuery", "AuthDBMAuthoritative", "AuthDBMGroupFile", "AuthDBMType", + "AuthDBMUserFile", "AuthDefaultAuthoritative", "AuthDigestAlgorithm", "AuthDigestDomain", + "AuthDigestFile", "AuthDigestGroupFile", "AuthDigestNcCheck", "AuthDigestNonceFormat", + "AuthDigestNonceLifetime", "AuthDigestProvider", "AuthDigestQop", "AuthDigestShmemSize", + "AuthFormAuthoritative", "AuthFormBody", "AuthFormDisableNoStore", "AuthFormFakeBasicAuth", + "AuthFormLocation", "AuthFormLoginRequiredLocation", "AuthFormLoginSuccessLocation", + "AuthFormLogoutLocation", "AuthFormMethod", "AuthFormMimetype", "AuthFormPassword", + "AuthFormProvider", "AuthFormSitePassphrase", "AuthFormSize", "AuthFormUsername", "AuthGroupFile", + "AuthLDAPAuthoritative", "AuthLDAPAuthorizePrefix", "AuthLDAPAuthzEnabled", + "AuthLDAPBindAuthoritative", "AuthLDAPBindDN", "AuthLDAPBindPassword", "AuthLDAPCharsetConfig", + "AuthLDAPCompareAsUser", "AuthLDAPCompareDNOnServer", "AuthLDAPDereferenceAliases", + "AuthLDAPEnabled", "AuthLDAPFrontPageHack", "AuthLDAPGroupAttribute", "AuthLDAPGroupAttributeIsDN", + "AuthLDAPGroupAttributeIsDN", "AuthLDAPInitialBindAsUser", "AuthLDAPInitialBindPattern", + "AuthLDAPMaxSubGroupDepth", "AuthLDAPRemoteUserAttribute", "AuthLDAPRemoteUserIsDN", + "AuthLDAPSearchAsUser", "AuthLDAPSubGroupAttribute", "AuthLDAPSubGroupClass", "AuthLDAPURL", + "AuthMerging", "AuthName", "AuthnCacheContext", "AuthnCacheEnable", "AuthnCacheProvideFor", + "AuthnCacheProvider", "AuthnCacheSOCache", "AuthnCacheTimeout", "AuthnzFcgiCheckAuthnProvider", + "AuthnzFcgiDefineProvider", "AuthType", "AuthUserFile", "AuthzDBDLoginToReferer", "AuthzDBDQuery", + "AuthzDBDRedirectQuery", "AuthzDBMAuthoritative", "AuthzDBMType", "AuthzDefaultAuthoritative", + "AuthzGroupFileAuthoritative", "AuthzLDAPAuthoritative", "AuthzOwnerAuthoritative", + "AuthzSendForbiddenOnFailure", "AuthzUserAuthoritative", "BalancerGrowth", "BalancerInherit", + "BalancerMember", "BalancerNonce", "BalancerPersist", "BrowserMatch", "BrowserMatchNoCase", + "BrowserMatchNoCase", "BS2000Account", "BufferedLogs", "DeflateBufferSize", "BufferSize", + "CacheDefaultExpire", "CacheDetailHeader", "CacheDirLength", "CacheDirLevels", "CacheDisable", + "CacheEnable", "CacheExpiryCheck", "cachefile", "CacheForceCompletion", "CacheGcClean", + "CacheGcDaily", "CacheGcInterval", "CacheGcMemUsage", "CacheGcUnused", "CacheHeader", + "CacheIgnoreCacheControl", "CacheIgnoreHeaders", "CacheIgnoreNoLastMod", "CacheIgnoreQueryString", + "CacheIgnoreURLSessionIdentifiers", "CacheKeyBaseURL", "CacheLastModifiedFactor", "CacheLock", + "CacheLockMaxAge", "CacheLockPath", "CacheMaxExpire", "CacheMaxFileSize", "CacheMinExpire", + "CacheMinFileSize", "CacheNegotiatedDocs", "CacheQuickHandler", "CacheReadSize", "CacheReadTime", + "CacheRoot", "MCacheSize", "CacheSocache", "CacheSocacheMaxSize", "CacheSocacheMaxTime", + "CacheSocacheMinTime", "CacheSocacheReadSize", "CacheSocacheReadTime", "CacheStaleOnError", + "CacheStoreExpired", "CacheStoreNoStore", "CacheStorePrivate", "CacheTimeMargin", "CaseFilter", + "CaseFilterIn", "CGIDScriptTimeout", "CGIMapExtension", "CGIPassAuth", "CGIVar", "CharsetDefault", + "CharsetOptions", "CharsetSourceEnc", "CheckCaseOnly", "CheckSpelling", "ChildperUserID", "ChrootDir", + "ClientRecheckTime", "ContentDigest", "CookieDomain", "CookieExpires", "CookieLog", "CookieName", + "CookieStyle", "CookieTracking", "CoreDumpDirectory", "CustomLog", "DAV", "DAVDepthInfinity", + "DAVGenericLockDB", "DAVLockDB", "DAVMinTimeout", "DBDExptime", "DBDInitSQL", "DBDKeep", "DBDMax", + "DBDMin", "DBDParams", "DBDPersist", "DBDPrepareSQL", "DBDriver", "DefaultIcon", "DefaultLanguage", + "DefaultRuntimeDir", "DefaultType", "Define", "DeflateBufferSize", "DeflateCompressionLevel", + "DeflateFilterNote", "DeflateInflateLimitRequestBody", "DeflateInflateRatioBurst", + "DeflateInflateRatioLimit", "DeflateMemLevel", "DeflateWindowSize", "Deny", "Deny", "DirectoryIndex", + "DirectorySlash", "DirectoryCheckHandler", "DirectoryIndex", "DirectoryIndexRedirect", "DirectoryMatch", + "DirectorySlash", "VirtualDocumentRoot", "DocumentRoot", "DTracePrivileges", "DumpIOInput", + "DumpIOLogLevel", "DumpIOOutput", "EnableExceptionHook", "EnableMMAP", "EnableSendfile", "ErrorDocument", + "ErrorLog", "ErrorLogFormat", "ExpiresActive", "ExpiresByType", "ExpiresDefault", "ExtendedStatus", + "ExtFilterDefine", "ExtFilterOptions", "FallbackResource", "FancyIndexing", "FileETag", "Files", + "FilesMatch", "FilterChain", "FilterDeclare", "FilterProtocol", "FilterProvider", "FilterTrace", + "ForceLanguagePriority", "ForceType", "ForensicLog", "GlobalLog", "GprofDir", "AuthGroupFile", "Group", + "AuthDBMGroupFile", "AuthLDAPGroupAttribute", "AuthLDAPGroupAttributeIsDN", "AuthzGroupFileAuthoritative", + "H2AltSvc", "H2AltSvcMaxAge", "H2Direct", "H2MaxSessionStreams", "H2MaxWorkerIdleSeconds", "H2MaxWorkers", + "H2MinWorkers", "H2ModernTLSOnly", "H2Push", "H2PushDiarySize", "H2PushPriority", "H2SerializeHeaders", + "H2SessionExtraFiles", "H2StreamMaxMemSize", "H2TLSCoolDownSecs", "H2TLSWarmUpSize", "H2Upgrade", + "H2WindowSize", "Header", "RequestHeader", "HeaderName", "HeaderName", "HeartbeatAddress", + "HeartbeatListen", "HeartbeatMaxServers", "HeartbeatStorage", "HostnameLookups", "IdentityCheck", + "IdentityCheckTimeout", "IfDefine", "IfModule", "IfVersion", "ImapBase", "ImapDefault", "ImapMenu", + "Include", "IncludeOptional", "IndexHeadInsert", "IndexIgnore", "IndexIgnoreReset", "IndexOptions", + "IndexOrderDefault", "IndexStyleSheet", "InputSed", "ISAPIAppendLogToErrors", "ISAPIAppendLogToQuery", + "ISAPICacheFile", "ISAPIFakeAsync", "ISAPILogNotSupported", "ISAPIReadAheadBuffer", "KeepAlive", + "KeepAliveTimeout", "MaxKeepAliveRequests", "KeepAliveTimeout", "KeptBodySize", "LanguagePriority", + "ForceLanguagePriority", "LDAPCacheEntries", "LDAPCacheTTL", "LDAPConnectionPoolTTL", + "LDAPConnectionTimeout", "LDAPLibraryDebug", "LDAPOpCacheEntries", "LDAPOpCacheTTL", "LDAPReferralHopLimit", + "LDAPReferrals", "LDAPRetries", "LDAPRetryDelay", "LDAPSharedCacheFile", "LDAPSharedCacheSize", + "LDAPTimeout", "LDAPTrustedCA", "LDAPTrustedCAType", "LDAPTrustedClientCert", "LDAPTrustedGlobalCert", + "LDAPTrustedMode", "LDAPVerifyServerCert", "LimitRequestBody", "RLimitMEM", "LimitRequestFields", + "LimitRequestFieldSize", "LimitRequestLine", "LimitExcept", "LimitInternalRecursion", "LimitRequestBody", + "LimitRequestFields", "LimitRequestFieldsize", "LimitRequestLine", "LimitXMLRequestBody", "LoadFile", + "LoadModule", "Location", "LocationMatch", "LockFile", "LogFormat", "LogIOTrackTTFB", "RewriteLogLevel", + "LogLevel", "LogMessage", "LuaAuthzProvider", "Lua_____ByteCodeHack", "LuaCodeCache", "LuaHookAccessChecker", + "LuaHookAuthChecker", "LuaHookCheckUserID", "LuaHookFixups", "LuaHookInsertFilter", "LuaHookLog", + "LuaHookMapToStorage", "LuaHookTranslateName", "LuaHookTypeChecker", "LuaInherit", "LuaInputFilter", + "LuaMapHandler", "LuaOutputFilter", "LuaPackageCPath", "LuaPackagePath", "LuaQuickHandler", "LuaRoot", + "LuaScope", "MaxClientConnections", "MaxClients", "MaxConnectionsPerChild", "MaxKeepAliveRequests", + "MaxMemFree", "MaxRangeOverlaps", "MaxRangeReversals", "MaxRanges", "MaxRequestsPerChild", + "MaxRequestsPerThread", "MaxRequestWorkers", "MaxSpareServers", "MaxSpareThreads", "MaxThreads", + "MaxThreadsPerChild", "MCacheMaxObjectCount", "MCacheMaxObjectSize", "MCacheMaxStreamingBuffer", + "MCacheMinObjectSize", "MCacheRemovalAlgorithm", "MCacheSize", "MemcacheConnTTL", "MergeTrailers", + "MetaDir", "MetaFiles", "MetaSuffix", "MimeMagicFile", "MinSpareServers", "MinSpareThreads", "mmapfile", + "ModemStandard", "ModMimeUsePathInfo", "MultiviewsMatch", "Mutex", "NameVirtualHost", "NoProxy", + "NumServers", "NWSSLTrustedCerts", "NWSSLUpgradeable", "Options", "RewriteOptions", "IndexOptions", + "Order", "IndexOrderDefault", "Order", "IndexOrderDefault", "OutputSed", "PassEnv", "php_admin_flag", + "php_admin_value", "php_flag", "php_value", "PidFile", "Port", "PrivilegesMode", "FilterProtocol", + "Protocol", "ProtocolEcho", "Protocols", "ProtocolsHonorOrder", "ProxyPass", "ProxyPassMatch", + "ProxyPassReverse", "ProxyRequests", "ProxyAddHeaders", "ProxyBadHeader", "ProxyBlock", "ProxyDomain", + "ProxyErrorOverride", "ProxyExpressDBMFile", "ProxyExpressDBMType", "ProxyExpressEnable", + "ProxyFtpDirCharset", "ProxyFtpEscapeWildcards", "ProxyFtpListOnWildcard", "ProxyHCExpr", "ProxyHCTemplate", + "ProxyHCTPsize", "ProxyHTMLBufSize", "ProxyHTMLCharsetOut", "ProxyHTMLDoctype", "ProxyHTMLEnable", + "ProxyHTMLEvents", "ProxyHTMLExtended", "ProxyHTMLFixups", "ProxyHTMLInterp", "ProxyHTMLLinks", + "ProxyHTMLMeta", "ProxyHTMLStripComments", "ProxyHTMLURLMap", "ProxyIOBufferSize", "ProxyMatch", + "ProxyMaxForwards", "ProxyPass", "ProxyPassMatch", "ProxyPassReverse", "ProxyPassInherit", + "ProxyPassInterpolateEnv", "ProxyPassMatch", "ProxyPassReverse", "ProxyPassReverseCookieDomain", + "ProxyPassReverseCookiePath", "ProxyPreserveHost", "ProxyReceiveBufferSize", "ProxyRemote", + "ProxyRemoteMatch", "ProxyRequests", "ProxySCGIInternalRedirect", "ProxySCGISendfile", "ProxySet", + "ProxySourceAddress", "ProxyStatus", "ProxyTimeout", "ProxyVia", "QualifyRedirectURL", "ReadmeName", + "Redirect", "RedirectMatch", "RedirectTemp", "RedirectPermanent", "RedirectMatch", "RedirectPermanent", + "RedirectTemp", "ReflectorHeader", "RemoteIPHeader", "RemoteIPInternalProxy", "RemoteIPInternalProxyList", + "RemoteIPProxiesHeader", "RemoteIPTrustedProxy", "RemoteIPTrustedProxyList", "RemoveCharset", + "RemoveEncoding", "RemoveHandler", "RemoveInputFilter", "RemoveLanguage", "RemoveOutputFilter", "RemoveType", + "RequestHeader", "RequestReadTimeout", "RequestTimeout", "Require", "RewriteBase", "RewriteCond", + "RewriteEngine", "RewriteLock", "RewriteLog", "RewriteLogLevel", "RewriteLogLevel", "RewriteMap", + "RewriteOptions", "RewriteRule", "RLimitCPU", "RLimitMEM", "RLimitNPROC", "Satisfy", "ScoreboardFile", + "ScoreBoardFile", "Script", "ScriptAlias", "ScriptAlias", "ScriptAliasMatch", "ScriptInterpreterSource", + "ScriptLog", "ScriptLogBuffer", "ScriptLogLength", "Scriptsock", "ScriptSock", "SecureListen", + "SeeRequestTail", "SerfCluster", "SerfPass", "ServerAdmin", "ServerAlias", "ServerLimit", "ServerName", + "ServerPath", "ServerRoot", "ServerSignature", "ServerTokens", "Session", "SessionCookieName", + "SessionCookieName2", "SessionCookieRemove", "SessionCryptoCipher", "SessionCryptoDriver", + "SessionCryptoPassphrase", "SessionCryptoPassphraseFile", "SessionDBDCookieName", "SessionDBDCookieName2", + "SessionDBDCookieRemove", "SessionDBDDeleteLabel", "SessionDBDInsertLabel", "SessionDBDPerUser", + "SessionDBDSelectLabel", "SessionDBDUpdateLabel", "SessionEnv", "SessionExclude", "SessionHeader", + "SessionInclude", "SessionMaxAge", "SetEnvIfNoCase", "SetEnv", "SetEnvIf", "SetEnvIfNoCase", "SetEnvIf", + "SetEnvIfExpr", "SetEnvIfNoCase", "SetHandler", "SetInputFilter", "SetOutputFilter", "SimpleProcCount", + "SimpleThreadCount", "SSIAccessEnable", "SSIEndTag", "SSIErrorMsg", "SSIEtag", "SSILastModified", + "SSILegacyExprParser", "SSIStartTag", "SSITimeFormat", "SSIUndefinedEcho", "SSLLog", "SSLLogLevel", + "StartServers", "StartThreads", "Substitute", "SubstituteInheritBefore", "SubstituteMaxLineLength", + "Suexec", "SuexecUserGroup", "ThreadLimit", "ThreadsPerChild", "ThreadStackSize", "KeepAliveTimeout", + "AuthnCacheTimeout", "TraceEnable", "TransferLog", "TrustedProxy", "TypesConfig", "UnDefine", "UnsetEnv", + "UseCanonicalName", "UseCanonicalPhysicalPort", "User", "AuthUserFile", "UserDir", "AuthDBMUserFile", + "Anonymous_NoUserID", "UserDir", "VHostCGIMode", "VHostCGIPrivs", "VHostGroup", "VHostPrivs", "VHostSecure", + "VHostUser", "VirtualDocumentRoot", "VirtualDocumentRootIP", "VirtualHost", "VirtualScriptAlias", + "VirtualScriptAliasIP", "Win32DisableAcceptEx", "XBitHack", "xml2EncAlias", "xml2EncDefault", + "xml2StartParse", "SecFilterEngine", "from", "SSLOptions", "SSLRequireSSL", "SSLRequire" +} +local literals = { + "on", "off", "deny", "denied", "all", "allow", "basic", "valid-user", "append", "unset", "set", "eq", + "any", "email" +} + +local symbols = {} +for _,lt in ipairs(literals) do + symbols[lt] = "literal" + symbols[lt:gsub("%f[%w]%l", string.upper)] = "literal" +end +for _,kw in ipairs(keywords) do + symbols[kw] = "keyword" +end + +local url_syntax = { + patterns = { + { pattern = "[%%$]%d+", type = "keyword2" }, + { pattern = "[%%$]%{[%w_:%-]+%}", type = "keyword2" }, + { pattern = "[^%%$%s]", type = "string" } + }, + symbols = {} +} +local xml_syntax = { + patterns = {{ pattern = { '"', '"', '\\' }, type = "string" }}, + symbols = {} +} + +syntax.add { + name = ".htaccess File", + files = { PATHSEP .. "^%.htaccess$" }, + comment = "#", + patterns = { + -- Comments + { pattern = "#.*\n", type = "comment" }, + -- Strings + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { '`', '`', '\\' }, type = "string" }, + -- URLs + { pattern = { "%w-://", "%f[%s]" }, type = "string", syntax = url_syntax }, + { pattern = { "%f[%S]/", "%f[%s]" }, type = "string", syntax = url_syntax }, + -- Mime types + { pattern = "%f[%w]application/[%w%._+-]+", type = "keyword2" }, + { pattern = "%f[%w]font/[%w%._+-]+", type = "keyword2" }, + { pattern = "%f[%w]image/[%w%._+-]+", type = "keyword2" }, + { pattern = "%f[%w]text/[%w%._+-]+", type = "keyword2" }, + { pattern = "%f[%w]audio/[%w%._+-]+", type = "keyword2" }, + { pattern = "%f[%w]video/[%w%._+-]+", type = "keyword2" }, + -- IPs + { pattern = "%d+%.%d+%.%d+%.%d+", type = "keyword2" }, + { pattern = "%d+%.%d+%.%d+%.%d+/%d+", type = "keyword2" }, + { regex = "([a-f0-9:]+:+)+[a-f0-9]+", type = "keyword2" }, + -- Emails + { pattern = "%w+@%w+%.%w+", type = "keyword2" }, + -- Rewrite option sections + { pattern = "%f[%S]%b[]", type = "number" }, + -- XML tags + { pattern = { "" }, type = "literal", syntax = xml_syntax }, + -- Variables + { pattern = "[%%$]%d+", type = "keyword2" }, + { pattern = "[%%$]%{[%w_:%-]+%}", type = "keyword2" }, + -- Numbers + { pattern = "A?%d+", type = "number" }, + -- Operators + { pattern = "%f[%S][!=+%-]+", type = "operator" }, + -- Regex (TODO: improve this, it's pretty naive and only works on some regex) + { pattern = "%f[^%s!]%^%S*", type = "literal" }, + { pattern = "%f[^%s!]%S*%$", type = "literal" }, + { pattern = "%f[^%s!]%b()", type = "literal" }, + -- Everything else + { pattern = "[%a_][%w_-]*", type = "symbol" }, + }, + symbols = symbols +} diff --git a/debian/extra/plugins/language_ignore.lua b/debian/extra/plugins/language_ignore.lua new file mode 100644 index 0000000..2192d7a --- /dev/null +++ b/debian/extra/plugins/language_ignore.lua @@ -0,0 +1,20 @@ +-- mod-version:3 + +local syntax = require "core.syntax" +local style = require "core.style" +local common = require "core.common" + +style.syntax["ignore"] = { common.color "#72B886" } +style.syntax["exclude"] = { common.color "#F36161" } + +syntax.add { + name = ".ignore file", + files = { PATHSEP .. "%..*ignore$" }, + comment = "#", + patterns = { + { regex = "^ *#.*$", type = "comment" }, + { regex = { "(?=^ *!.)", "$" }, type = "ignore" }, + { regex = { "(?=.)", "$" }, type = "exclude" }, + }, + symbols = {} +} diff --git a/debian/extra/plugins/language_ini.lua b/debian/extra/plugins/language_ini.lua new file mode 100644 index 0000000..b517e0e --- /dev/null +++ b/debian/extra/plugins/language_ini.lua @@ -0,0 +1,27 @@ +-- mod-version:3 + +local syntax = require "core.syntax" + +syntax.add { + name = "INI", + files = { "%.ini$", "%.inf$", "%.cfg$", PATHSEP .. "%.editorconfig$", "%.theme$", "%.dockitem$", "%.desktop$" }, + comment = ';', + patterns = { + { pattern = ";.*", type = "comment" }, + { pattern = "#.*", type = "comment" }, + { pattern = { "%[", "%]" }, type = "keyword" }, + + { pattern = { '"""', '"""', '\\' }, type = "string" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'''", "'''" }, type = "string" }, + { pattern = { "'", "'" }, type = "string" }, + { pattern = "[A-Za-z0-9_%.%-]+%s*%f[=]", type = "function" }, + { pattern = "[%-+]?[0-9_]+%.[0-9_]+", type = "number" }, + { pattern = "[%-+]?[0-9_]+", type = "number" }, + { pattern = "[a-z]+", type = "symbol" }, + }, + symbols = { + ["true"] = "literal", + ["false"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_java.lua b/debian/extra/plugins/language_java.lua new file mode 100644 index 0000000..873d827 --- /dev/null +++ b/debian/extra/plugins/language_java.lua @@ -0,0 +1,87 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Java", + files = { "%.java$" }, + comment = "//", + patterns = { + { pattern = "//.*", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "'\\x%x?%x?%x?%x'", type = "string" }, -- character hexadecimal escape sequence + { pattern = "'\\u%x%x%x%x'", type = "string" }, -- character unicode escape sequence + { pattern = "'\\?.'", type = "string" }, -- character literal + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { regex = "(?>\\w+\\.?)+(?=\\s+\\w++\\s*\\=\\s*)", type = "function" }, -- Class name when creating an object + { regex = "[A-Z][A-Z_]+", type = "keyword2" }, -- Constants + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["abstract"] = "keyword", + ["assert"] = "keyword", + ["break"] = "keyword", + ["case"] = "keyword", + ["catch"] = "keyword", + ["class"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["default"] = "keyword", + ["do"] = "keyword", + ["else"] = "keyword", + ["enum"] = "keyword", + ["extends"] = "keyword", + ["final"] = "keyword", + ["finally"] = "keyword", + ["for"] = "keyword", + ["if"] = "keyword", + ["goto"] = "keyword", + ["implements"] = "keyword", + ["import"] = "keyword", + ["instanceof"] = "keyword", + ["interface"] = "keyword", + ["native"] = "keyword", + ["new"] = "keyword", + ["package"] = "keyword", + ["permits"] = "keyword", + ["private"] = "keyword", + ["protected"] = "keyword", + ["public"] = "keyword", + ["record"] = "keyword", + ["return"] = "keyword", + ["sealed"] = "keyword", + ["static"] = "keyword", + ["strictfp"] = "keyword", + ["super"] = "keyword", + ["switch"] = "keyword", + ["synchronized"] = "keyword", + ["this"] = "keyword", + ["throw"] = "keyword", + ["throws"] = "keyword", + ["transient"] = "keyword", + ["try"] = "keyword", + ["var"] = "keyword", + ["void"] = "keyword", + ["volatile"] = "keyword", + ["while"] = "keyword", + ["yield"] = "keyword", + + ["boolean"] = "keyword2", + ["byte"] = "keyword2", + ["char"] = "keyword2", + ["double"] = "keyword2", + ["float"] = "keyword2", + ["int"] = "keyword2", + ["long"] = "keyword2", + ["short"] = "keyword2", + + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal" + } +} diff --git a/debian/extra/plugins/language_jiyu.lua b/debian/extra/plugins/language_jiyu.lua new file mode 100644 index 0000000..dbf9d0e --- /dev/null +++ b/debian/extra/plugins/language_jiyu.lua @@ -0,0 +1,93 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Jiyu", + files = { "%.jiyu$", "%.jyu$" }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { "\"\"\"", "\"\"\"" }, type = "string" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "0b[0-1]+", type = "number" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.]*", type = "number" }, + { pattern = "-?%.?%d+?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "[<>~=+-*/]=", type = "operator" }, + { pattern = "[..]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[#@]?[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + -- Keywords + ["func"] = "keyword", + ["if"] = "keyword", + ["else"] = "keyword", + ["for"] = "keyword", + ["while"] = "keyword", + ["defer"] = "keyword", + ["return"] = "keyword", + ["switch"] = "keyword", + ["case"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["fallthrough"] = "keyword", + ["struct"] = "keyword", + ["union"] = "keyword", + ["enum"] = "keyword", + ["using"] = "keyword", + ["var"] = "keyword", + ["let"] = "keyword", + ["typealias"] = "keyword", + ["library"] = "keyword", + ["framework"] = "keyword", + ["temporary_c_vararg"] = "keyword2"; + -- Builtin procedures and directives + ["cast"] = "keyword2", + ["sizeof"] = "keyword2", + ["alignof"] = "keyword2", + ["strideof"] = "keyword2", + ["offsetof"] = "keyword2", + ["type_of"] = "keyword2", + ["type_info"] = "keyword2", + ["#if"] = "keyword2", + ["#load"] = "keyword2", + ["#import"] = "keyword2", + ["#clang_import"] = "keyword2", + ["#file"] = "keyword2", + ["#filepath"] = "keyword2", + ["#line"] = "keyword2", + + ["@c_function"] = "keyword2", + ["@export"] = "keyword2", + ["@flags"] = "keyword2", + ["@metaprogram"] = "keyword2", + -- Types + ["string"] = "keyword2", + ["int"] = "keyword2", + ["uint"] = "keyword2", + ["uint8"] = "keyword2", + ["uint16"] = "keyword2", + ["uint32"] = "keyword2", + ["uint64"] = "keyword2", + ["uint128"] = "keyword2", + ["int8"] = "keyword2", + ["int16"] = "keyword2", + ["int32"] = "keyword2", + ["int64"] = "keyword2", + ["int128"] = "keyword2", + ["float"] = "keyword2", + ["double"] = "keyword2", + ["void"] = "keyword2", + ["bool"] = "keyword2", + ["Type"] = "keyword2", + + -- Literals + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + } +} diff --git a/debian/extra/plugins/language_json.lua b/debian/extra/plugins/language_json.lua new file mode 100644 index 0000000..26d05a2 --- /dev/null +++ b/debian/extra/plugins/language_json.lua @@ -0,0 +1,34 @@ +-- mod-version:3 priority:110 + +local syntax = require "core.syntax" + +syntax.add { + name = "JSON", + + files = { + "%.json$", + "%.cjson$", + "%.jsonc$", + "%.ipynb$", + }, + + comment = "//", + block_comment = {"/*", "*/"}, + patterns = { + + -- cjson support + { pattern = "//.*", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + + { regex = [["(?:[^"\\]|\\.)*"()\s*:]], type = { "keyword", "normal" } }, -- key + { regex = [["(?:[^"\\]|\\.)*"]], type = "string" }, -- value + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "null", type = "literal" }, + { pattern = "true", type = "literal" }, + { pattern = "false", type = "literal" } + }, + symbols = { } +} + diff --git a/debian/extra/plugins/language_jsx.lua b/debian/extra/plugins/language_jsx.lua new file mode 100644 index 0000000..941e786 --- /dev/null +++ b/debian/extra/plugins/language_jsx.lua @@ -0,0 +1,73 @@ +-- mod-version:3 +-- Almost identical to JS, with the exception that / shouldn't denote a regex. Current JS syntax highlighter will highlight half the document due to closing tags. +local syntax = require "core.syntax" + +syntax.add { + name = "JSX", + files = { "%.jsx$", "%.astro$" }, + comment = "//", + block_comment = { "/*", "*/" }, + patterns = { + { pattern = "//.*", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "`", "`", '\\' }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "%f[^<]/?[%a_][%w_]*", type = "function" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["async"] = "keyword", + ["await"] = "keyword", + ["break"] = "keyword", + ["case"] = "keyword", + ["catch"] = "keyword", + ["class"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["debugger"] = "keyword", + ["default"] = "keyword", + ["delete"] = "keyword", + ["do"] = "keyword", + ["else"] = "keyword", + ["export"] = "keyword", + ["extends"] = "keyword", + ["finally"] = "keyword", + ["for"] = "keyword", + ["from"] = "keyword", + ["function"] = "keyword", + ["get"] = "keyword", + ["if"] = "keyword", + ["import"] = "keyword", + ["in"] = "keyword", + ["instanceof"] = "keyword", + ["let"] = "keyword", + ["new"] = "keyword", + ["return"] = "keyword", + ["set"] = "keyword", + ["static"] = "keyword", + ["super"] = "keyword", + ["switch"] = "keyword", + ["throw"] = "keyword", + ["try"] = "keyword", + ["typeof"] = "keyword", + ["var"] = "keyword", + ["void"] = "keyword", + ["while"] = "keyword", + ["with"] = "keyword", + ["yield"] = "keyword", + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + ["undefined"] = "literal", + ["arguments"] = "keyword2", + ["Infinity"] = "keyword2", + ["NaN"] = "keyword2", + ["this"] = "keyword2", + }, +} diff --git a/debian/extra/plugins/language_julia.lua b/debian/extra/plugins/language_julia.lua new file mode 100644 index 0000000..347592f --- /dev/null +++ b/debian/extra/plugins/language_julia.lua @@ -0,0 +1,112 @@ +-- mod-version:3 +-- Support for the Julia programming language: +-- Covers the most used keywords up to Julia version 1.6.4 + +local syntax = require "core.syntax" + +syntax.add { + name = "Julia", + files = { "%.jl$" }, + comment = "#", + patterns = { + {pattern = {"#=", "=#"}, type="comment" }, + {pattern = "#.*$", type="comment" }, + { pattern = { 'icxx"""', '"""' }, type = "string", syntax = ".cpp" }, + { pattern = { 'cxx"""', '"""' }, type = "string", syntax = ".cpp" }, + { pattern = { 'py"""', '"""' }, type = "string", syntax = ".py" }, + { pattern = { 'js"""', '"""' }, type = "string", syntax = ".js" }, + { pattern = { 'md"""', '"""' }, type = "string", syntax = ".md" }, + { pattern = "%d%w*[%.-+*//]", type = "number" }, + { pattern = "0[oO_][0-7]+", type = "number" }, + { pattern = "-?0x[%x_]+", type = "number" }, + { pattern = "-?0b[%x_]+", type = "number" }, + { pattern = "-?%d+_%d", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[^%d%g]%:%a*", type = "function" }, + { pattern = "[%+%-=/%*%^%%<>!~|&%:]",type = "operator"}, + { pattern = '""".*"""', type = "string" }, + { pattern = '".*"', type = "string" }, + { pattern = '[bv]".*"', type = "string" }, + { pattern = 'r".*$', type = "string" }, + { pattern = "'\\.*'", type = "string" }, + { pattern = "'.'", type = "string" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "%g*!", type="function"}, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + -- keywords + ["baremodule"] = "keyword", + ["begin"] = "keyword", + ["break"] = "keyword", + ["catch"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["do"] = "keyword", + ["Dict"] = "keyword", + ["Set"] = "keyword", + ["Union"] = "keyword", + ["else"] = "keyword", + ["elseif"] = "keyword", + ["end"] = "keyword", + ["export"] = "keyword", + ["finally"] = "keyword", + ["for"] = "keyword", + ["function"] = "keyword", + ["global"] = "keyword", + ["if"] = "keyword", + ["in"] = "keyword", + ["import"] = "keyword", + ["let"] = "keyword", + ["local"] = "keyword", + ["macro"] = "keyword", + ["type"] = "keyword", + ["module"] = "keyword", + ["mutable"] = "keyword", + ["quote"] = "keyword", + ["return"] = "keyword", + ["try"] = "keyword", + ["typeof"] = "keyword", + ["using"] = "keyword", + ["while"] = "keyword", + ["where"] = "keyword", + + -- types + ["struct"] = "keyword2", + ["abstract"] = "keyword2", + ["primitive"] = "keyword2", + ["mutable"] = "keyword2", + ["Char"] = "keyword2", + ["Bool"] = "keyword2", + ["Int"] = "keyword2", + ["Integer"] = "keyword2", + ["Int8"] = "keyword2", + ["UInt8"] = "keyword2", + ["Int16"] = "keyword2", + ["UInt16"] = "keyword2", + ["Int32"] = "keyword2", + ["UInt32"] = "keyword2", + ["Int64"] = "keyword2", + ["UInt64"] = "keyword2", + ["Int128"] = "keyword2", + ["UInt128"] = "keyword2", + ["Float16"] = "keyword2", + ["Float32"] = "keyword2", + ["Float64"] = "keyword2", + ["Vector"] = "keyword2", + ["Matrix"] = "keyword2", + ["Ref"] = "keyword2", + ["String"] = "keyword2", + ["Function"] = "keyword2", + ["Number"] = "keyword2", + + -- literals + ["missing"] = "literal", + ["true"] = "literal", + ["false"] = "literal", + ["nothing"] = "literal", + ["Inf"] = "literal", + ["NaN"] = "literal", + } +} diff --git a/debian/extra/plugins/language_kdl.lua b/debian/extra/plugins/language_kdl.lua new file mode 100644 index 0000000..a08a0bb --- /dev/null +++ b/debian/extra/plugins/language_kdl.lua @@ -0,0 +1,84 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +local identifier = "\"?[^%d%s\\/%(%){}<>;%[%]=,\"][^%s\\/%(%){}<>;%[%]=,\"]*\"?" + +syntax.add { + name = "KDL", + files = { "%.kdl" }, + space_handling = false, + comment = "//", + block_comment = {"/*", "*/"}, + patterns = { + { + pattern = "^%s*".. identifier .."%s*", + type = "keyword" + },-- + { pattern = "%s+", type = "normal" }, + { + pattern = "[{;]%s*()" .. identifier .. "%s*", + type = {"normal", "keyword"} + },-- + { pattern = { "r#+\"", "\"#+" }, type = "string" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = "[%-+]?0x[%x_]+", type = "number" }, + { pattern = "[%-+]?0b[01_]+", type = "number" }, + { pattern = "[%-+]?0o[0-7_]+", type = "number" }, + { + pattern = "[%-+]?[%d_]+%.[%d_]+e[%-+]?[%d_]+", + type = "number" + }, + { pattern = "[%-+]?[%d_]+%.[%d_]+", type = "number" }, + { pattern = "[%-+]?[%d_]+e[%-+]?[%d_]+", type = "number" }, + { pattern = "[%-+]?[%d_]+", type = "number" }, + { pattern = "/[%-/].-\n", type = "comment" }, + { pattern = {"/%*", "%*/"}, type = "comment" }, + { pattern = identifier, type = "keyword2" }, + { + pattern = "%(()" .. identifier .. "()%)", + type = {"normal", "function", "normal"} + }, + }, + symbols = { + ["null"] = "literal", + ["true"] = "literal", + ["false"] = "literal", + ["i8"] = "function", + ["i32"] = "function", + ["i16"] = "function", + ["i64"] = "function", + ["u8"] = "function", + ["u32"] = "function", + ["u16"] = "function", + ["u64"] = "function", + ["isize"] = "function", + ["usize"] = "function", + ["f32"] = "function", + ["f64"] = "function", + ["decimal64"] = "function", + ["decimal128"] = "function", + ["date-time"] = "function", + ["time"] = "function", + ["date"] = "function", + ["duration"] = "function", + ["decimal"] = "function", + ["currency"] = "function", + ["country-2"] = "function", + ["country-3"] = "function", + ["country-subdivision"] = "function", + ["email"] = "function", + ["idn-email"] = "function", + ["hostname"] = "function", + ["idn-hostname"] = "function", + ["ipv4"] = "function", + ["ipv6"] = "function", + ["url"] = "function", + ["url-reference"] = "function", + ["irl"] = "function", + ["irl-reference"] = "function", + ["url-template"] = "function", + ["uuid"] = "function", + ["regex"] = "function", + ["base64"] = "function", + }, +} diff --git a/debian/extra/plugins/language_kotlin.lua b/debian/extra/plugins/language_kotlin.lua new file mode 100644 index 0000000..c3d6b4f --- /dev/null +++ b/debian/extra/plugins/language_kotlin.lua @@ -0,0 +1,124 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Kotlin", + files = { "%.kt$" }, + comment = "//", + block_comment = { "/*", "*/" }, + patterns = { + { pattern = "//.*", type = "comment" }, -- Comment, single-line + { pattern = { "/%*", "%*/" }, type = "comment" }, -- Comment, multi-line + { pattern = { '"', '"', '\\' }, type = "string" }, -- String, quotation marks + { pattern = { "'", "'", '\\' }, type = "string" }, -- String, apices + { pattern = "'\\x%x?%x?%x?%x'", type = "string" }, -- Character hexadecimal escape sequence + { pattern = "'\\u%x%x%x%x'", type = "string" }, -- Character unicode escape sequence + { pattern = "'\\?.'", type = "string" }, -- Character literal + { pattern = "-?0x%x+", type = "number" }, -- ? + { pattern = "-?%d+[%deE]*f?", type = "number" }, -- ? + { pattern = "-?%.?%d+f?", type = "number" }, -- ? + { regex = [[\-\>(?=\s)]], type = "operator" }, -- Lambda + { regex = [[\.{2}\!~|&]", type = "operator" }, -- Operators + { regex = [[\?(?=\.)]], type = "operator" }, -- ?. operator + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- Function/Method/Class + { regex = "`[\\w_\\s]+`(?=\\s*\\()", type = "function" }, -- Test Method + { regex = [[let(?=\s\{)]], type = "function" }, -- ? operator + { regex = [[\?\:(?=\s?)]], type = "operator" }, -- elvis operator + { regex = [[this(?=\.?\@?)]], type = "keyword" }, -- this keyword + { regex = "\\@\\w+", type = "keyword2" }, -- Annotations + { regex = [[[a-zA-Z]+\@(?=\s?[a-zA-Z])]], type = "keyword2" }, -- Annotations (this pattern is lower priority than the `this keyword` pattern) + { regex = "[A-Z][A-Z_]+", type = "keyword2" }, -- Constants, FULL UPPERCASE + { pattern = "import()%s+()[%w_.]+", type = { "keyword", "normal", "normal" } }, + { pattern = "[%a_][%w_]*", type = "symbol" }, -- ? + }, + symbols = { + -- Hard keywords + ["as"] = "keyword", + ["break"] = "keyword", + ["class"] = "keyword", + ["continue"] = "keyword", + ["do"] = "keyword", + ["else"] = "keyword", + ["for"] = "keyword", + ["fun"] = "keyword", + ["if"] = "keyword", + ["in"] = "keyword", + ["!in"] = "keyword", + ["interface"] = "keyword", + ["is"] = "keyword", + ["!is"] = "keyword", + ["object"] = "keyword", + ["package"] = "keyword", + ["return"] = "keyword", + ["super"] = "keyword", + ["this"] = "keyword", + ["throw"] = "keyword", + ["try"] = "keyword", + ["typealias"] = "keyword", + ["typeof"] = "keyword", + ["val"] = "keyword", + ["var"] = "keyword", + ["when"] = "keyword", + ["while"] = "keyword", + + -- Soft keywords + ["by"] = "keyword", + ["catch"] = "keyword", + ["constructor"] = "keyword", + ["delegate"] = "keyword", + ["dynamic"] = "keyword", + ["field"] = "keyword", + ["file"] = "keyword", + ["finally"] = "keyword", + ["get"] = "keyword", + ["import"] = "keyword", + ["init"] = "keyword", + ["param"] = "keyword", + ["property"] = "keyword", + ["receiver"] = "keyword", + ["set"] = "keyword", + ["setparam"] = "keyword", + ["value"] = "keyword", + ["where"] = "keyword", + + -- Modifier keywords + ["abstract"] = "keyword", + ["actual"] = "keyword", + ["annotation"] = "keyword", + ["companion"] = "keyword", + ["const"] = "keyword", + ["crossinline"] = "keyword", + ["data"] = "keyword", + ["enum"] = "keyword", + ["expect"] = "keyword", + ["external"] = "keyword", + ["final"] = "keyword", + ["inline"] = "keyword", + ["inner"] = "keyword", + ["infix"] = "keyword", + ["internal"] = "keyword", + ["lateinit"] = "keyword", + ["noinline"] = "keyword", + ["open"] = "keyword", + ["operator"] = "keyword", + ["out"] = "keyword", + ["override"] = "keyword", + ["private"] = "keyword", + ["protected"] = "keyword", + ["public"] = "keyword", + ["reified"] = "keyword", + ["sealed"] = "keyword", + ["suspend"] = "keyword", + ["tailrec"] = "keyword", + ["vararg"] = "keyword", + + -- Special identifiers + ["it"] = "keyword", + + -- Boolean + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_lilypond.lua b/debian/extra/plugins/language_lilypond.lua new file mode 100644 index 0000000..a3f84f1 --- /dev/null +++ b/debian/extra/plugins/language_lilypond.lua @@ -0,0 +1,22 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "LilyPond", + files = { "%.i?ly$" }, + comment = "%%", + block_comment = { "%%{", "%%}" }, + patterns = { + { pattern = "#%(()[%a_]%S*", type = { "operator", "function" } }, + { pattern = {"%%{", "%%}"}, type = "comment" }, + { pattern = "%%.*", type = "comment" }, + { pattern = "#[%w_-]*", type = "keyword2" }, + { pattern = "\\%a%w+", type = "keyword" }, + { pattern = "\\\\", type = "operator" }, + { pattern = "[%(%){}%[%]<>=/~%-%_']", type = "operator" }, + { pattern = {'"', '"', "\\"}, type = "string" }, + { pattern = "-?%.?%d+", type = "number" }, + }, + symbols = {} +} + diff --git a/debian/extra/plugins/language_liquid.lua b/debian/extra/plugins/language_liquid.lua new file mode 100644 index 0000000..ad40a79 --- /dev/null +++ b/debian/extra/plugins/language_liquid.lua @@ -0,0 +1,145 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +local liquid_syntax = { + patterns = { + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?%d+[%d%.]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "%w+", type = "symbol" }, + }, + symbols = { + ["abs"] = "keyword2", + ["and"] = "operator", + ["append"] = "keyword2", + ["assign"] = "keyword", + ["at_least"] = "keyword2", + ["at_most"] = "keyword2", + ["break"] = "keyword", + ["camelcase"] = "keyword2", + ["capitalize"] = "keyword2", + ["capture"] = "keyword", + ["endcapture"] = "keyword", + ["case"] = "keyword", + ["ceil"] = "keyword2", + ["comment"] = "keyword", + ["endcomment"] = "keyword", + ["concat"] = "keyword2", + ["contains"] = "operator", + ["cycle"] = "keyword", + ["date"] = "keyword2", + ["decrement"] = "keyword", + ["default"] = "keyword2", + ["divided_by"] = "keyword2", + ["downcase"] = "keyword2", + ["else"] = "keyword", + ["elsif"] = "keyword", + ["false"] = "literal", + ["first"] = "keyword2", + ["floor"] = "keyword2", + ["for"] = "keyword", + ["endfor"] = "keyword", + ["forloop"] = "literal", + ["handleize"] = "keyword2", + ["handle"] = "keyword2", + ["if"] = "keyword", + ["endif"] = "keyword", + ["increment"] = "keyword", + ["index0"] = "literal", + ["index"] = "literal", + ["in"] = "operator", + ["join"] = "keyword2", + ["last"] = "keyword2", + ["length"] = "literal", + ["limit"] = "keyword", + ["lstrip"] = "keyword", + ["map"] = "keyword2", + ["minus"] = "keyword2", + ["modulo"] = "keyword2", + ["nil"] = "literal", + ["null"] = "literal", + ["offset"] = "keyword2", + ["or"] = "operator", + ["pluralize"] = "keyword2", + ["plus"] = "keyword2", + ["prepend"] = "keyword2", + ["raw"] = "keyword", + ["endraw"] = "keyword", + ["removefirst"] = "keyword2", + ["remove"] = "keyword2", + ["replacefirst"] = "keyword2", + ["replace"] = "keyword2", + ["reversed"] = "operator", + ["reverse"] = "keyword2", + ["rindex0"] = "literal", + ["rindex"] = "literal", + ["round"] = "keyword2", + ["rstrip"] = "keyword2", + ["size"] = "keyword2", + ["slice"] = "keyword2", + ["sort"] = "keyword2", + ["split"] = "keyword2", + ["strip"] = "keyword2", + ["strip_newlines"] = "keyword2", + ["times"] = "keyword2", + ["true"] = "literal", + ["truncate"] = "keyword2", + ["truncatewords"] = "keyword2", + ["uniq"] = "keyword2", + ["unless"] = "keyword", + ["endunless"] = "keyword", + ["upcase"] = "keyword2", + ["when"] = "keyword", + ["where"] = "keyword2" + + }, +} + +syntax.add { + name = "Liquid", + files = { "%.liquid?$" }, + patterns = { + { pattern = { "{%%", "%%}" }, syntax = liquid_syntax, type = "function" }, + { pattern = { "{{", "}}" }, syntax = liquid_syntax, type = "function" }, + { + pattern = { + "<%s*[sS][cC][rR][iI][pP][tT]%s+[tT][yY][pP][eE]%s*=%s*" .. + "['\"]%a+/[jJ][aA][vV][aA][sS][cC][rR][iI][pP][tT]['\"]%s*>", + "<%s*/[sS][cC][rR][iI][pP][tT]>" + }, + syntax = ".js", + type = "function" + }, + { + pattern = { + "<%s*[sS][cC][rR][iI][pP][tT]%s*>", + "<%s*/%s*[sS][cC][rR][iI][pP][tT]>" + }, + syntax = ".js", + type = "function" + }, + { + pattern = { + "<%s*[sS][tT][yY][lL][eE][^>]*>", + "<%s*/%s*[sS][tT][yY][lL][eE]%s*>" + }, + syntax = ".css", + type = "function" + }, + { pattern = { "" }, type = "comment" }, + { pattern = { '%f[^>][^<]', '%f[<{]' }, type = "normal" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "%f[^<]![%a_][%w_]*", type = "keyword2" }, + { pattern = "%f[^<][%a_][%w_]*", type = "function" }, + { pattern = "%f[^<]/[%a_][%w_]*", type = "function" }, + { pattern = "[%a_][%w_]*", type = "keyword" }, + { pattern = "[/<>=]", type = "operator" } + }, + symbols = {}, +} + diff --git a/debian/extra/plugins/language_lobster.lua b/debian/extra/plugins/language_lobster.lua new file mode 100644 index 0000000..a0e133f --- /dev/null +++ b/debian/extra/plugins/language_lobster.lua @@ -0,0 +1,79 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Lobster", + files = "%.lobster$", + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + + { pattern = "struct%s()[%a_][%w_]*", type = { "keyword", "keyword2" } }, + { pattern = "class%s()[%a_][%w_]*", type = { "keyword", "keyword2" } }, + { pattern = "[%w_]+%s*%f[{]", type = "keyword2" }, + + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { '"""', '"""' }, type = "string" }, + { pattern = "0x%x+", type = "number" }, + { pattern = "%d+[%d%.eE]*f?", type = "number" }, + { pattern = "%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&%?]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["import"] = "keyword", + ["from"] = "keyword", + ["def"] = "keyword", + ["fn"] = "keyword", + ["return"] = "keyword", + ["program"] = "keyword", + ["private"] = "keyword", + ["resource"] = "keyword", + + -- not really keywords but provides control-flow constructs + ["if"] = "keyword", + ["guard"] = "keyword", + ["for"] = "keyword", + ["while"] = "keyword", + ["else"] = "keyword", + + ["enum"] = "keyword", + ["enum_flags"] = "keyword", + + ["int"] = "keyword2", + ["float"] = "keyword2", + ["string"] = "keyword2", + ["any"] = "keyword2", + ["void"] = "keyword2", + + ["is"] = "keyword", + ["typeof"] = "keyword", + ["var"] = "keyword", + ["let"] = "keyword", + ["pakfile"] = "keyword", + ["switch"] = "keyword", + ["case"] = "keyword", + ["default"] = "keyword", + ["namespace"] = "keyword", + ["constructor"] = "keyword", + ["operator"] = "keyword", + ["super"] = "keyword", + ["abstract"] = "keyword", + ["attribute"] = "keyword", + ["member"] = "keyword", + ["member_frame"] = "keyword", + ["static"] = "keyword", + ["static_frame"] = "keyword", + ["not"] = "keyword", + ["and"] = "keyword", + ["or"] = "keyword", + ["struct"] = "keyword", + ["class"] = "keyword", + + ["nil"] = "literal", + }, +} + diff --git a/debian/extra/plugins/language_lox.lua b/debian/extra/plugins/language_lox.lua new file mode 100644 index 0000000..a6b3c43 --- /dev/null +++ b/debian/extra/plugins/language_lox.lua @@ -0,0 +1,34 @@ +-- mod-version:3 +local syntax = require 'core.syntax' + +syntax.add { + name = "Lox", + files = { "%.lox$" }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { '"', '"' }, type = "string" }, + { pattern = "%a[%w_]*()%s*%f[(]", type = {"function", "normal"} }, + { pattern = "[%a_][%w_]*%s*%f[(]", type = "function" }, + { pattern = "%d+%.?%d*", type = "number" }, + { pattern = "%a%w*", type = "symbol" }, + }, + symbols = { + ["and"] = "keyword", + ["class"] = "keyword", + ["else"] = "keyword", + ["false"] = "literal", + ["for"] = "keyword", + ["fun"] = "keyword", + ["if"] = "keyword", + ["nil"] = "literal", + ["or"] = "keyword", + ["print"] = "keyword", + ["return"] = "keyword", + ["super"] = "keyword2", + ["this"] = "keyword2", + ["true"] = "keyword", + ["var"] = "keyword", + ["while"] = "keyword", + }, +} diff --git a/debian/extra/plugins/language_make.lua b/debian/extra/plugins/language_make.lua new file mode 100644 index 0000000..eed01f5 --- /dev/null +++ b/debian/extra/plugins/language_make.lua @@ -0,0 +1,19 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Makefile", + files = { PATHSEP .. "[Mm]akefile$", "%.mk$" }, + comment = "#", + patterns = { + { pattern = "#.*", type = "comment" }, + { pattern = [[\.]], type = "normal" }, + { pattern = "$[@^<%%?+|*]", type = "keyword2" }, + { pattern = "$%(.-%)", type = "symbol" }, + { pattern = "%f[%w_][%d%.]+%f[^%w_]", type = "number" }, + { pattern = "%..*:", type = "keyword2" }, + { pattern = ".*:", type = "function" }, + }, + symbols = { + }, +} diff --git a/debian/extra/plugins/language_marte.lua b/debian/extra/plugins/language_marte.lua new file mode 100644 index 0000000..3410e17 --- /dev/null +++ b/debian/extra/plugins/language_marte.lua @@ -0,0 +1,42 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "MARTe", + files = { "%.mrt$", "%.marte$" }, + comment = "//", + block_comment = { "/*", "*/" }, + patterns = { + { pattern = "//.*", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "%-?%.inf", type = "number" }, + { pattern = "%.NaN", type = "number" }, + { + pattern = "Class%s+()=()%s+[%a_][%w_:]*", + type = { "keyword", "operator", "keyword2"} + }, + { + pattern = "Type%s+()=()%s+[%a_][%w_]*", + type = { "keyword", "operator", "keyword2"} + }, + { + pattern = "[%+%$][%a_][%w_]+%s()=", + type = {"function", "operator"} + }, + { pattern = "=%s+()[%a_][%w_]+", type = "string" }, + { + pattern = "[%a_][%w_]+%s()=", + type = {"keyword", "operator"} + }, + { pattern = "0x%x+", type = "number" }, + { pattern = "%d+[%d%.'eE]*f?", type = "number" }, + { pattern = "%.?%d+f?", type = "number" }, + { pattern = "%a[%w_]+", type = "literal" }, + }, + symbols = { + ["true"] = "number", + ["false"] = "number", + }, +} diff --git a/debian/extra/plugins/language_meson.lua b/debian/extra/plugins/language_meson.lua new file mode 100644 index 0000000..ebf906f --- /dev/null +++ b/debian/extra/plugins/language_meson.lua @@ -0,0 +1,36 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Meson", + files = { PATHSEP .. "meson%.build$", PATHSEP .. "meson_options%.txt$" }, + comment = "#", + patterns = { + { pattern = "#.*", type = "comment" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "'''", "'''" }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+%d*", type = "number" }, + { pattern = "[%+%-=/%%%*!]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["if"] = "keyword", + ["then"] = "keyword", + ["else"] = "keyword", + ["elif"] = "keyword", + ["endif"] = "keyword", + ["foreach"] = "keyword", + ["endforeach"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["and"] = "keyword", + ["not"] = "keyword", + ["or"] = "keyword", + ["in"] = "keyword", + ["true"] = "literal", + ["false"] = "literal", + }, +} + diff --git a/debian/extra/plugins/language_miniscript.lua b/debian/extra/plugins/language_miniscript.lua new file mode 100644 index 0000000..afe0a2b --- /dev/null +++ b/debian/extra/plugins/language_miniscript.lua @@ -0,0 +1,102 @@ +-- mod-version:3 +local syntax = require 'core.syntax' + +syntax.add { + name = "MiniScript", + files = { "%.ms$" }, + comment = "//", + patterns = { + { pattern = "//.*", type = "comment" }, + { pattern = { '"', '"' }, type = "string" }, + { pattern = "[<>!=]=", type = "operator" }, + { pattern = "[%+%-%*%/%^@<>:]", type = "operator" }, + { pattern = "%d%.%d*[eE][-+]?%d+", type = "number" }, + { pattern = "%d%.%d*", type = "number" }, + { pattern = "%.?%d*[eE][-+]?%d+", type = "number" }, + { pattern = "%.?%d+", type = "number" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["if"] = "keyword", + ["not"] = "keyword", + ["and"] = "keyword", + ["or"] = "keyword", + ["else"] = "keyword", + ["then"] = "keyword", + ["for"] = "keyword", + ["in"] = "keyword", + ["while"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["function"] = "keyword", + ["end"] = "keyword", + ["return"] = "keyword", + ["new"] = "keyword", + ["isa"] = "keyword", + ["self"] = "keyword2", + + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + ["globals"] = "literal", + ["locals"] = "literal", + ["outer"] = "literal", + + -- Built-in types's classes + ["number"] = "literal", + ["string"] = "literal", + ["list"] = "literal", + ["map"] = "literal", + ["funcRef"] = "literal", + + -- Intrinsic functions + ["abs"] = "function", + ["acos"] = "function", + ["asin"] = "function", + ["atan"] = "function", + ["bitAnd"] = "function", + ["bitOr"] = "function", + ["bitXor"] = "function", + ["ceil"] = "function", + ["char"] = "function", + ["code"] = "function", + ["cos"] = "function", + ["floor"] = "function", + ["hash"] = "function", + ["hasIndex"] = "function", + ["indexes"] = "function", + ["indexOf"] = "function", + ["insert"] = "function", + ["join"] = "function", + ["len"] = "function", + ["log"] = "function", + ["lower"] = "function", + ["pi"] = "function", + ["pop"] = "function", + ["print"] = "function", + ["pull"] = "function", + ["push"] = "function", + ["range"] = "function", + ["remove"] = "function", + ["replace"] = "function", + ["rnd"] = "function", + ["round"] = "function", + ["shuffle"] = "function", + ["sign"] = "function", + ["sin"] = "function", + ["slice"] = "function", + ["sort"] = "function", + ["split"] = "function", + ["sqrt"] = "function", + ["str"] = "function", + ["sum"] = "function", + ["tan"] = "function", + ["time"] = "function", + ["upper"] = "function", + ["val"] = "function", + ["values"] = "function", + ["version"] = "function", + ["wait"] = "function", + ["yield"] = "function", + }, +} diff --git a/debian/extra/plugins/language_moon.lua b/debian/extra/plugins/language_moon.lua new file mode 100644 index 0000000..3ccb7ea --- /dev/null +++ b/debian/extra/plugins/language_moon.lua @@ -0,0 +1,64 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "MoonScript", + files = "%.moon$", + headers = "^#!.*[ /]moon", + comment = "--", + patterns = { + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "%[%[", "%]%]" }, type = "string" }, + { pattern = "%-%-.-\n", type = "comment" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "%.%.%.?", type = "keyword2" }, + { pattern = "[<>~=]=", type = "keyword2" }, + { pattern = "[%+%-=/%*%^%%#<>]", type = "keyword2" }, + { pattern = "[%a_][%w_]*%s*%f[(\"{]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = {"\\", "[%a_][%w_]*"}, type = "function" }, + { pattern = {"%.", "[%a_][%w_]*"}, type = "function" }, + { pattern = "@[%a_][%w_]*", type = "keyword2" }, + { pattern = "@", type = "keyword2" }, + { pattern = "!", type = "keyword2" }, + { pattern = "[%p]", type = "keyword" }, + }, + symbols = { + ["if"] = "keyword", + ["then"] = "keyword", + ["else"] = "keyword", + ["when"] = "keyword", + ["elseif"] = "keyword", + ["do"] = "keyword", + ["->"] = "keyword", + ["while"] = "keyword", + ["for"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["export"] = "keyword", + ["unless"] = "keyword", + ["return"] = "keyword", + ["in"] = "keyword", + ["not"] = "keyword", + ["and"] = "keyword", + ["or"] = "keyword", + ["import"] = "keyword", + ["as"] = "keyword", + ["from"] = "keyword", + ["class"] = "keyword", + ["extends"] = "keyword", + ["switch"] = "keyword", + ["with"] = "keyword", + ["using"] = "keyword", + ["super"] = "keyword2", + ["self"] = "keyword2", + ["#"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + ["nil"] = "literal", + }, +} + diff --git a/debian/extra/plugins/language_nelua.lua b/debian/extra/plugins/language_nelua.lua new file mode 100644 index 0000000..c29d969 --- /dev/null +++ b/debian/extra/plugins/language_nelua.lua @@ -0,0 +1,119 @@ +-- mod-version:3 + +-- to better understand these comments, see this section from rxi's article +-- https://rxi.github.io/lite_an_implementation_overview.html#syntax_highlighting + +-- first, we need to require the syntax module +local syntax = require "core.syntax" + +--[[ + then, we'll add a new syntax to the syntax module, lite-xl matches Lua patterns + against the source code in order to highlight the code. +]] +syntax.add { + -- the extension of source code + files = "%.nelua$", + -- this add support for shebang, is not rare to add #!/usr/local/bin/lua to make + -- lua scripts executable, here we add support for it for nelua + headers = "^#!.*[ /]nelua", + -- tells to lite how to toggle comments + comment = "--", + -- finally the patterns, is a table of tables, + -- each entry is a table with some fields, especially with "pattern" and "type" fields. + patterns = { + --[[ + ["pattern"] field: + Describes a syntax pattern, this is done with Lua Patterns + you can learn it works here: https://www.lua.org/manual/5.4/manual.html#6.4.1 + + The pattern can be a string or a table, when is a string, then is just a + pattern that match everything, when is a table, then it follows this + logic: + { range_start_pattern, range_end_pattern [, escape_character] } + + The matched range_start_pattern and range_end_pattern text will be highlighted, but the + text between them will not. + + ["syntax"] field: + Optional field, when set, the text between matched ranges will use syntax from another language, + a good common known example of this is using javascript syntax inside a `script` element: + https://github.com/lite-xl/lite-xl/blob/df667ad28e9995f8cb79dab64e6039f095c202f4/data/plugins/language_html.lua#L17-L23 + + ["type"] field: + Set the style that should be used, this is defined on the "style" file from + the lite-xl's source, at "data/core/style.lua". + ]] + { + pattern = {"##%[=*%[", "%]=*%]"}, + syntax = ".lua", + type = "function", + }, + { + pattern = {"#|", "|#"}, + syntax = ".lua", + type = "function", + }, + { + pattern = {"##", "\n"}, + syntax = ".lua", + type = "function", + }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "%[%[", "%]%]" }, type = "string" }, + { pattern = { "%-%-%[=*%[", "%]=*%]"}, type = "comment" }, + { pattern = "%-%-.-\n", type = "comment" }, + { pattern = "0x%x+%.%x*[pP][-+]?%d+", type = "number" }, + { pattern = "0x%x+%.%x*", type = "number" }, + { pattern = "0x%.%x+[pP][-+]?%d+", type = "number" }, + { pattern = "0x%.%x+", type = "number" }, + { pattern = "0x%x+[pP][-+]?%d+", type = "number" }, + { pattern = "0x%x+", type = "number" }, + { pattern = "%d%.%d*[eE][-+]?%d+", type = "number" }, + { pattern = "%d%.%d*", type = "number" }, + { pattern = "%.?%d*[eE][-+]?%d+", type = "number" }, + { pattern = "<%S[%w+%._,%s*'\"()<>]-%S>", type = "keyword2" }, + { pattern = "%.?%d+", type = "number" }, + { pattern = "%.%.%.?", type = "operator" }, + { pattern = "[<>~=]=", type = "operator" }, + { pattern = "[%+%-=/%*%^%%#<>]", type = "operator" }, + { pattern = "[%a_][%w_]*()%s*%f[(\"'{]", type = {"function", "normal"} }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "::[%a_][%w_]*::", type = "function" }, + }, + -- special symbols, like keywords + symbols = { + -- lua symbols + ["if"] = "keyword", + ["then"] = "keyword", + ["else"] = "keyword", + ["elseif"] = "keyword", + ["end"] = "keyword", + ["do"] = "keyword", + ["function"] = "keyword", + ["repeat"] = "keyword", + ["until"] = "keyword", + ["while"] = "keyword", + ["for"] = "keyword", + ["break"] = "keyword", + ["return"] = "keyword", + ["local"] = "keyword", + ["in"] = "keyword", + ["not"] = "keyword", + ["and"] = "keyword", + ["or"] = "keyword", + ["goto"] = "keyword", + ["self"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + ["nil"] = "literal", + + -- nelua symbols + ["global"] = "keyword", + ["switch"] = "keyword", + ["case"] = "keyword", + ["defer"] = "keyword", + ["continue"] = "keyword", + ["nilptr"] = "keyword", + }, +} diff --git a/debian/extra/plugins/language_nginx.lua b/debian/extra/plugins/language_nginx.lua new file mode 100644 index 0000000..7124c1a --- /dev/null +++ b/debian/extra/plugins/language_nginx.lua @@ -0,0 +1,394 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +-- Copied from https://github.com/shanoor/vscode-nginx/blob/master/syntaxes/nginx.tmLanguage + +syntax.add { + name = "Nginx", + files = { "%.conf$" }, + comment = "#", + patterns = { + { pattern = "#.*", type = "comment" }, + { pattern = { '"', '"', }, type = "string" }, + { pattern = { "'", "'", }, type = "string" }, + { pattern = "[0-9]", type = "number" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "%$%w+", type = "keyword2" } + }, + symbols = { + -- constant.language.module.events + ["events"] = "keyword", + + -- constant.language.module.http + ["http"] = "keyword", + + -- constant.language.directive.module.main + ["daemon"] = "keyword", + ["env"] = "keyword", + ["debug_points"] = "keyword", + ["error_log"] = "keyword", + ["log_not_found"] = "keyword", + ["include"] = "keyword", + ["lock_file"] = "keyword", + ["master_process"] = "keyword", + ["pid"] = "keyword", + ["ssl_engine"] = "keyword", + ["timer_resolution"] = "keyword", + ["types_hash_max_size"] = "keyword", + ["user"] = "keyword", + ["worker_cpu_affinity"] = "keyword", + ["worker_priority"] = "keyword", + ["worker_processes"] = "keyword", + ["worker_rlimit_core"] = "keyword", + ["worker_rlimit_nofile"] = "keyword", + ["worker_rlimit_sigpending"] = "keyword", + ["working_directory"] = "keyword", + ["try_files"] = "keyword", + + -- constant.language.directive.module.events + ["accept_mutex"] = "keyword", + ["accept_mutex_delay"] = "keyword", + ["debug_connection"] = "keyword", + ["devpoll_changes"] = "keyword", + ["devpoll_events"] = "keyword", + ["epoll_events"] = "keyword", + ["kqueue_changes"] = "keyword", + ["kqueue_events"] = "keyword", + ["multi_accept"] = "keyword", + ["rtsig_signo"] = "keyword", + ["rtsig_overflow_events"] = "keyword", + ["rtsig_overflow_test"] = "keyword", + ["rtsig_overflow_threshold"] = "keyword", + ["use"] = "keyword", + ["worker_connections"] = "keyword", + + -- constant.language.directive.module.http + ["alias"] = "keyword", + ["chunked_transfer_encoding"] = "keyword", + ["client_body_in_file_only"] = "keyword", + ["client_body_buffer_size"] = "keyword", + ["client_body_temp_path"] = "keyword", + ["client_body_timeout"] = "keyword", + ["client_header_buffer_size"] = "keyword", + ["client_header_timeout"] = "keyword", + ["client_max_body_size"] = "keyword", + ["default_type"] = "keyword", + ["error_page"] = "keyword", + ["index"] = "keyword", + ["internal"] = "keyword", + ["keepalive_timeout"] = "keyword", + ["keepalive_requests"] = "keyword", + ["large_client_header_buffers"] = "keyword", + ["limit_except"] = "keyword", + ["limit_rate"] = "keyword", + ["listen"] = "keyword", + ["location"] = "keyword", + ["msie_padding"] = "keyword", + ["msie_refresh"] = "keyword", + ["optimize_server_names"] = "keyword", + ["port_in_redirect"] = "keyword", + ["recursive_error_pages"] = "keyword", + ["reset_timedout_connection"] = "keyword", + ["resolver"] = "keyword", + ["resolver_timeout"] = "keyword", + ["root"] = "keyword", + ["satisfy_any"] = "keyword", + ["send_timeout"] = "keyword", + ["sendfile"] = "keyword", + ["server"] = "keyword", + ["server_name"] = "keyword", + ["server_names_hash_max_size"] = "keyword", + ["server_names_hash_bucket_size"] = "keyword", + ["tcp_nodelay"] = "keyword", + ["tcp_nopush"] = "keyword", + ["types"] = "keyword", + ["try_files"] = "keyword", + + -- constant.language.module.http.addition + ["add_before_body"] = "keyword", + ["add_after_body"] = "keyword", + ["addition_types"] = "keyword", + + -- constant.language.module.http.access + ["allow"] = "keyword", + ["deny"] = "keyword", + + -- constant.language.module.http.auth_basic + ["auth_basic"] = "keyword", + ["auth_basic_user_file"] = "keyword", + + -- constant.language.module.http.auth_jwt + ["auth_jwt"] = "keyword", + ["auth_jwt_header_set"] = "keyword", + ["auth_jwt_claim_set"] = "keyword", + ["auth_jwt_key_file"] = "keyword", + + -- constant.language.module.http.autoindex + ["autoindex"] = "keyword", + ["autoindex_exact_size"] = "keyword", + ["autoindex_format"] = "keyword", + ["autoindex_localtime"] = "keyword", + + -- constant.language.module.http.browser + ["ancient_browser"] = "keyword", + ["ancient_browser_value"] = "keyword", + ["modern_browser"] = "keyword", + ["modern_browser_value"] = "keyword", + + -- constant.language.module.http.charset + ["charset"] = "keyword", + ["charset_map"] = "keyword", + ["override_charset"] = "keyword", + ["source_charset"] = "keyword", + + -- constant.language.module.http.empty_gif + ["empty_gif"] = "keyword", + + -- constant.language.module.http.fastcgi + ["fastcgi_index"] = "keyword", + ["fastcgi_hide_header"] = "keyword", + ["fastcgi_ignore_client_abort"] = "keyword", + ["fastcgi_intercept_errors"] = "keyword", + ["fastcgi_param"] = "keyword", + ["fastcgi_pass"] = "keyword", + ["fastcgi_pass_header"] = "keyword", + ["fastcgi_read_timeout"] = "keyword", + ["fastcgi_redirect_errors"] = "keyword", + ["fa"] = "keyword", + ["stcgi_storefastcgi_store_access"] = "keyword", + ["fastcgi_buffers"] = "keyword", + ["fastcgi_buffers_size"] = "keyword", + ["fastcgi_temp_path"] = "keyword", + ["fastcgi_buffer_size"] = "keyword", + ["fastcgi_connect_timeout"] = "keyword", + ["fastcgi_send_timeout"] = "keyword", + ["fastcgi_split_path_info"] = "keyword", + + -- constant.language.module.http.geo + ["geo"] = "keyword", + + -- constant.language.module.http.gzip + ["gzip"] = "keyword", + ["gzip_buffers"] = "keyword", + ["gzip_comp_level"] = "keyword", + ["gzip_disable"] = "keyword", + ["gzip_http.version"] = "keyword", + ["gzip_min_length"] = "keyword", + ["gzip_proxied"] = "keyword", + ["gzip_types"] = "keyword", + ["gzip_vary"] = "keyword", + ["gzip_static"] = "keyword", + + -- constant.language.module.http.headers + ["add_header"] = "keyword", + ["expires"] = "keyword", + ["server_tokens"] = "keyword", + + -- constant.language.module.http.referer + ["valid_referers"] = "keyword", + + -- constant.language.module.http.limit_zone + ["limit_zone"] = "keyword", + ["limit_conn"] = "keyword", + + -- constant.language.module.http.limit_req + ["limit_req"] = "keyword", + ["limit_req_log_level"] = "keyword", + ["limit_req_status"] = "keyword", + ["limit_req_zone"] = "keyword", + + -- constant.language.module.http.log + ["access_log"] = "keyword", + ["log_format"] = "keyword", + + -- constant.language.module.http.map + ["map"] = "keyword", + ["map_hash_max_size"] = "keyword", + ["map_hash_bucket_size"] = "keyword", + + -- constant.language.module.http.memcached + ["memcached_pass"] = "keyword", + ["memcached_connect_timeout"] = "keyword", + ["memcached_send_timeout"] = "keyword", + ["memcached_read_timeout"] = "keyword", + ["memcached_buffer_size"] = "keyword", + ["memcached_next_upstream"] = "keyword", + + -- constant.language.module.http.proxy + ["proxy_buffer_size"] = "keyword2", + ["proxy_buffering"] = "keyword2", + ["proxy_buffers"] = "keyword2", + ["proxy_busy_buffers_size"] = "keyword2", + ["proxy_cache"] = "keyword2", + ["proxy_cache_background_update"] = "keyword2", + ["proxy_cache_bypass"] = "keyword2", + ["proxy_cache_convert_head"] = "keyword2", + ["proxy_cache_key"] = "keyword2", + ["proxy_cache_lock"] = "keyword2", + ["proxy_cache_lock_age"] = "keyword2", + ["proxy_cache_lock_timeout"] = "keyword2", + ["proxy_cache_max_range_offset"] = "keyword2", + ["proxy_cache_methods"] = "keyword2", + ["proxy_cache_min_uses"] = "keyword2", + ["proxy_cache_path"] = "keyword2", + ["proxy_cache_purge"] = "keyword2", + ["proxy_cache_revalidate"] = "keyword2", + ["proxy_cache_use_stale"] = "keyword2", + ["proxy_cache_valid"] = "keyword2", + ["proxy_connect_timeout"] = "keyword2", + ["proxy_headers_hash_bucket_size"] = "keyword2", + ["proxy_headers_hash_max_size"] = "keyword2", + ["proxy_hide_header"] = "keyword2", + ["proxy_http_version"] = "keyword2", + ["proxy_ignore_client_abort"] = "keyword2", + ["proxy_intercept_errors"] = "keyword2", + ["proxy_max_temp_file_size"] = "keyword2", + ["proxy_method"] = "keyword2", + ["proxy_next_upstream"] = "keyword2", + ["proxy_next_upstream_tries"] = "keyword2", + ["proxy_next_upstream_timeout"] = "keyword2", + ["proxy_pass"] = "keyword2", + ["proxy_pass_header"] = "keyword2", + ["proxy_pass_request_body"] = "keyword2", + ["proxy_pass_request_headers"] = "keyword2", + ["proxy_read_timeout"] = "keyword2", + ["proxy_redirect"] = "keyword2", + ["proxy_redirect_errors"] = "keyword2", + ["proxy_send_lowat"] = "keyword2", + ["proxy_send_timeout"] = "keyword2", + ["proxy_set_body"] = "keyword2", + ["proxy_set_header"] = "keyword2", + ["proxy_store"] = "keyword2", + ["proxy_store_access"] = "keyword2", + ["proxy_temp_file_write_size"] = "keyword2", + ["proxy_temp_path"] = "keyword2", + ["proxy_upstream_fail_timeout"] = "keyword2", + ["proxy_upstream_max_fails"] = "keyword2", + ["proxy_no_cache"] = "keyword2", + + -- constant.language.module.http.realip + ["set_real_ip_from"] = "keyword", + ["real_ip_header"] = "keyword", + ["real_ip_recursive"] = "keyword", + + -- constant.language.module.http.rewrite + ["break"] = "keyword", + ["if"] = "keyword", + ["return"] = "keyword", + ["rewrite"] = "keyword", + ["set"] = "keyword", + ["uninitialized_variable_warn"] = "keyword", + + -- constant.language.module.http.ssi + ["ssi"] = "keyword", + ["ssi_silent_errors"] = "keyword", + ["ssi_types"] = "keyword", + ["ssi_value_length"] = "keyword", + + -- constant.language.module.http.upstream + ["ip_hash"] = "keyword", + ["upstream"] = "keyword", + ["server"] = "keyword", + + -- constant.language.module.http.userid + ["userid"] = "keyword", + ["userid_domain"] = "keyword", + ["userid_expires"] = "keyword", + ["userid_name"] = "keyword", + ["userid_p3p"] = "keyword", + ["userid_path"] = "keyword", + ["userid_service"] = "keyword", + + -- constant.language.module.http.uwsgi + ["uwsgi_bind"] = "keyword", + ["uwsgi_buffer_size"] = "keyword", + ["uwsgi_buffering"] = "keyword", + ["uwsgi_buffers"] = "keyword", + ["uwsgi_busy_buffers_size"] = "keyword", + ["uwsgi_cache"] = "keyword", + ["uwsgi_cache_background_update"] = "keyword", + ["uwsgi_cache_bypass"] = "keyword", + ["uwsgi_cache_key"] = "keyword", + ["uwsgi_cache_lock"] = "keyword", + ["uwsgi_cache_lock_age"] = "keyword", + ["uwsgi_cache_lock_timeout"] = "keyword", + ["uwsgi_cache_max_range_offset"] = "keyword", + ["uwsgi_cache_methods"] = "keyword", + ["uwsgi_cache_min_uses"] = "keyword", + ["uwsgi_cache_path"] = "keyword", + ["uwsgi_cache_purge"] = "keyword", + ["uwsgi_cache_revalidate"] = "keyword", + ["uwsgi_cache_use_stale"] = "keyword", + ["uwsgi_cache_valid"] = "keyword", + ["uwsgi_connect_timeout"] = "keyword", + ["uwsgi_force_ranges"] = "keyword", + ["uwsgi_hide_header"] = "keyword", + ["uwsgi_ignore_client_abort"] = "keyword", + ["uwsgi_ignore_headers"] = "keyword", + ["uwsgi_intercept_errors"] = "keyword", + ["uwsgi_limit_rate"] = "keyword", + ["uwsgi_max_temp_file_size"] = "keyword", + ["uwsgi_modifier1"] = "keyword", + ["uwsgi_modifier2"] = "keyword", + ["uwsgi_next_upstream"] = "keyword", + ["uwsgi_next_upstream_timeout"] = "keyword", + ["uwsgi_next_upstream_tries"] = "keyword", + ["uwsgi_no_cache"] = "keyword", + ["uwsgi_param"] = "keyword", + ["uwsgi_pass"] = "keyword", + ["uwsgi_pass_header"] = "keyword", + ["uwsgi_pass_request_body"] = "keyword", + ["uwsgi_pass_request_headers"] = "keyword", + ["uwsgi_read_timeout"] = "keyword", + ["uwsgi_request_buffering"] = "keyword", + ["uwsgi_send_timeout"] = "keyword", + ["uwsgi_ssl_certificate"] = "keyword", + ["uwsgi_ssl_certificate_key"] = "keyword", + ["uwsgi_ssl_ciphers"] = "keyword", + ["uwsgi_ssl_crl"] = "keyword", + ["uwsgi_ssl_name"] = "keyword", + ["uwsgi_ssl_password_file"] = "keyword", + ["uwsgi_ssl_protocols"] = "keyword", + ["uwsgi_ssl_server_name"] = "keyword", + ["uwsgi_ssl_session_reuse"] = "keyword", + ["uwsgi_ssl_trusted_certificate"] = "keyword", + ["uwsgi_ssl_verify"] = "keyword", + ["uwsgi_ssl_verify_depth"] = "keyword", + ["uwsgi_store"] = "keyword", + ["uwsgi_store_access"] = "keyword", + ["uwsgi_temp_file_write_size"] = "keyword", + ["uwsgi_temp_path"] = "keyword", + + -- constant.language.directive.module.http + ["ssl"] = "keyword", + ["ssl_buffer_size"] = "keyword", + ["ssl_certificate"] = "keyword", + ["ssl_certificate_key"] = "keyword", + ["ssl_ciphers"] = "keyword", + ["ssl_client_certificate"] = "keyword", + ["ssl_crl"] = "keyword", + ["ssl_dhparam"] = "keyword", + ["ssl_ecdh_curve"] = "keyword", + ["ssl_password_file"] = "keyword", + ["ssl_prefer_server_ciphers"] = "keyword", + ["ssl_protocols"] = "keyword", + ["ssl_session_cache"] = "keyword", + ["ssl_session_ticket_key"] = "keyword", + ["ssl_session_tickets"] = "keyword", + ["ssl_session_timeout"] = "keyword", + ["ssl_stapling"] = "keyword", + ["ssl_stapling_file"] = "keyword", + ["ssl_stapling_responder"] = "keyword", + ["ssl_stapling_verify"] = "keyword", + ["ssl_trusted_certificate"] = "keyword", + ["ssl_verify_client"] = "keyword", + ["ssl_verify_depth"] = "keyword", + + ["true"] = "literal", + ["false"] = "literal", + ["on"] = "literal", + ["off"] = "literal", + ["all"] = "literal", + ["null"] = "literal" + }, +} diff --git a/debian/extra/plugins/language_nim.lua b/debian/extra/plugins/language_nim.lua new file mode 100644 index 0000000..425544e --- /dev/null +++ b/debian/extra/plugins/language_nim.lua @@ -0,0 +1,145 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +local patterns = {} + +local symbols = { + ["nil"] = "literal", + ["true"] = "literal", + ["false"] = "literal", +} + +local number_patterns = { + "0[bB][01][01_]*", + "0o[0-7][0-7_]*", + "0[xX]%x[%x_]*", + "%d[%d_]*%.%d[%d_]*[eE][-+]?%d[%d_]*", + "%d[%d_]*%.%d[%d_]*", + "%d[%d_]*", +} + +local type_suffix_patterns = {} + +for _, size in ipairs({"", "8", "16", "32", "64"}) do + table.insert(type_suffix_patterns, "'?[fuiFUI]"..size) +end + +for _, pattern in ipairs(number_patterns) do + for _, suffix in ipairs(type_suffix_patterns) do + table.insert(patterns, { pattern = pattern..suffix, type = "literal" }) + end + table.insert(patterns, { pattern = pattern, type = "literal" }) +end + +local keywords = { + "addr", "and", "as", "asm", + "bind", "block", "break", + "case", "cast", "concept", "const", "continue", "converter", + "defer", "discard", "distinct", "div", "do", + "elif", "else", "end", "enum", "except", "export", + "finally", "for", "from", "func", + "if", "import", "in", "include", "interface", "is", "isnot", "iterator", + "let", + "macro", "method", "mixin", "mod", + "not", "notin", + "object", "of", "or", "out", + "proc", "ptr", + "raise", "ref", "return", + "shl", "shr", "static", + "template", "try", "tuple", "type", + "using", + "var", + "when", "while", + "xor", + "yield", +} + +for _, keyword in ipairs(keywords) do + symbols[keyword] = "keyword" +end + +local standard_types = { + "bool", "byte", + "int", "int8", "int16", "int32", "int64", + "uint", "uint8", "uint16", "uint32", "uint64", + "float", "float32", "float64", + "char", "string", "cstring", + "pointer", + "typedesc", + "void", "auto", "any", + "untyped", "typed", + "clong", "culong", "cchar", "cschar", "cshort", "cint", "csize", "csize_t", + "clonglong", "cfloat", "cdouble", "clongdouble", "cuchar", "cushort", + "cuint", "culonglong", "cstringArray", +} + +for _, type in ipairs(standard_types) do + symbols[type] = "keyword2" +end + +local standard_generic_types = { + "range", + "array", "open[aA]rray", "varargs", "seq", "set", + "sink", "lent", "owned", +} + +for _, type in ipairs(standard_generic_types) do + table.insert(patterns, { pattern = type.."%f[%[]", type = "keyword2" }) + table.insert(patterns, { pattern = type.." +%f[%w]", type = "keyword2" }) +end + +local function string_pattern(start, stop, syntax) + return { + pattern = { start, stop, '\\' }, + type = "string", + syntax = syntax and { + patterns = syntax, + symbols = {}, + } or nil + } +end + +local interpolation_syntax = { + { pattern = { '{{', '}}' }, type = "string" }, + { pattern = { '{', '}', '\\' }, type = "keyword2", syntax = ".nim" }, + { pattern = "[%S][%w]*", type = "string" }, +} + +local user_patterns = { + -- comments + { pattern = { "##?%[", "]##?" }, type = "comment" }, + { pattern = "##?.-\n", type = "comment" }, + -- strings and chars + { pattern = { "'", "'", '\\' }, type = "literal" }, + string_pattern('"""', '"""%f[^"]'), + string_pattern('"' , '"' ), + string_pattern('\\"', '\\"' ), -- For highlighting strings inside iterpolated blocks + -- string interpolation + string_pattern('%&"""' , '"""%f[^"]', interpolation_syntax), + string_pattern('fmt"""', '"""%f[^"]', interpolation_syntax), + string_pattern('%&"' , '"' , interpolation_syntax), + string_pattern('fmt"' , '"' , interpolation_syntax), + -- function calls + { pattern = "[a-zA-Z][a-zA-Z0-9_]*%f[(]", type = "function" }, + -- identifiers + { pattern = "[A-Z][a-zA-Z0-9_]*", type = "keyword2" }, + { pattern = "[a-zA-Z][a-zA-Z0-9_]*", type = "symbol" }, + -- operators + { pattern = "%.%f[^.]", type = "normal" }, + { pattern = ":%f[ ]", type = "normal" }, + { pattern = "[=+%-*/<>@$~&%%|!?%^&.:\\]+", type = "operator" }, +} + +for _, pattern in ipairs(user_patterns) do + table.insert(patterns, pattern) +end + +local nim = { + name = "Nim", + files = { "%.nim$", "%.nims$", "%.nimble$" }, + comment = "#", + patterns = patterns, + symbols = symbols, +} + +syntax.add(nim) diff --git a/debian/extra/plugins/language_nix.lua b/debian/extra/plugins/language_nix.lua new file mode 100644 index 0000000..149c2fa --- /dev/null +++ b/debian/extra/plugins/language_nix.lua @@ -0,0 +1,87 @@ +-- mod-version:3 +-- https://nixos.wiki/wiki/Overview_of_the_Nix_Language +local syntax = require "core.syntax" + +local function merge_tables(a, b) + for _, v in pairs(b) do + table.insert(a, v) + end +end + +local default_symbols = { + ["import"] = "keyword2", + ["with"] = "keyword2", + ["builtins"] = "keyword2", + ["inherit"] = "keyword2", + ["assert"] = "keyword2", + ["let"] = "keyword2", + ["in"] = "keyword2", + ["rec"] = "keyword2", + ["if"] = "keyword", + ["else"] = "keyword", + ["then"] = "keyword", + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", +} + +local default_patterns = {} + +local string_interpolation = { + { pattern = {"%${", "}"}, type = "keyword2", syntax = { + patterns = default_patterns, + symbols = default_symbols, + }}, + { pattern = "[%S][%w]*", type = "string" }, +} + +merge_tables(default_patterns, { + { pattern = "#.*", type = "comment" }, + { pattern = {"/%*", "%*/"}, type = "comment" }, + { pattern = "-?%.?%d+", type = "number" }, + + -- interpolation + { pattern = {"%${", "}"}, type = "keyword2", syntax = { + patterns = default_patterns, + symbols = default_symbols, + }}, + { pattern = {'"', '"', '\\'}, type = "string", syntax = { + patterns = string_interpolation, + symbols = {}, + }}, + { pattern = {"''", "''"}, type = "string", syntax = { + patterns = string_interpolation, + symbols = {}, + }}, + + -- operators + { pattern = "[%+%-%?!>%*]", type = "operator" }, + { pattern = "/ ", type = "operator" }, + { pattern = "< ", type = "operator" }, + { pattern = "//", type = "operator" }, + { pattern = "&&", type = "operator" }, + { pattern = "%->", type = "operator" }, + { pattern = "||", type = "operator" }, + { pattern = "==", type = "operator" }, + { pattern = "!=", type = "operator" }, + { pattern = ">=", type = "operator" }, + { pattern = "<=", type = "operator" }, + + -- paths (function because its not used otherwise) + { pattern = "%.?%.?/[^%s%[%]%(%){};,:]+", type = "function" }, + { pattern = "~/[^%s%[%]%(%){};,:]+", type = "function" }, + { pattern = {"<", ">"}, type = "function" }, + + -- every other symbol + { pattern = "[%a%-%_][%w%-%_]*", type = "symbol" }, + { pattern = ";%.,:", type = "normal" }, +}) + +syntax.add { + name = "Nix", + files = {"%.nix$"}, + comment = "#", + block_comment = {"/*", "*/"}, + patterns = default_patterns, + symbols = default_symbols, +} diff --git a/debian/extra/plugins/language_objc.lua b/debian/extra/plugins/language_objc.lua new file mode 100644 index 0000000..8d1210b --- /dev/null +++ b/debian/extra/plugins/language_objc.lua @@ -0,0 +1,63 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Objective-C", + files = { "%.m$" }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { "#", "[^\\]\n" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "@[%a_][%w_]*", type = "keyword2" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["if"] = "keyword", + ["then"] = "keyword", + ["else"] = "keyword", + ["elseif"] = "keyword", + ["do"] = "keyword", + ["while"] = "keyword", + ["for"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["return"] = "keyword", + ["goto"] = "keyword", + ["struct"] = "keyword", + ["union"] = "keyword", + ["typedef"] = "keyword", + ["enum"] = "keyword", + ["extern"] = "keyword", + ["static"] = "keyword", + ["volatile"] = "keyword", + ["const"] = "keyword", + ["inline"] = "keyword", + ["switch"] = "keyword", + ["case"] = "keyword", + ["default"] = "keyword", + ["auto"] = "keyword", + ["const"] = "keyword", + ["void"] = "keyword", + ["int"] = "keyword2", + ["short"] = "keyword2", + ["long"] = "keyword2", + ["float"] = "keyword2", + ["double"] = "keyword2", + ["char"] = "keyword2", + ["unsigned"] = "keyword2", + ["bool"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + ["NULL"] = "literal", + ["nil"] = "literal", + }, +} + diff --git a/debian/extra/plugins/language_odin.lua b/debian/extra/plugins/language_odin.lua new file mode 100644 index 0000000..84f422a --- /dev/null +++ b/debian/extra/plugins/language_odin.lua @@ -0,0 +1,162 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Odin", + files = "%.odin$", + comment = "//", + block_comment = { "/*", "*/" }, + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "`", "`" }, type = "string" }, + { pattern = "0b[01_]+", type = "number" }, + { pattern = "0o[0-7_]+", type = "number" }, + { pattern = "0[dz][%d_]+", type = "number" }, + { pattern = "0x[%da-fA-F_]+", type = "number" }, + { pattern = "-?%d+[%d%._e]*i?", type = "number" }, + { pattern = "[<>~=+-*/]=", type = "operator" }, + { pattern = "%.%.", type = "operator" }, + { pattern = "[%+%-=/%*%^%%<>!~|&:%?]", type = "operator" }, + { pattern = "%$[%a_][%w_]*", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[#@][%a_][%w_]*", type = "keyword2" }, + { pattern = "[#@]%b()", type = "keyword2" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + -- Keywords + ["package"] = "keyword", + ["import"] = "keyword", + ["foreign"] = "keyword", + ["when"] = "keyword", + ["if"] = "keyword", + ["else"] = "keyword", + ["for"] = "keyword", + ["defer"] = "keyword", + ["return"] = "keyword", + ["switch"] = "keyword", + ["case"] = "keyword", + ["in"] = "keyword", + ["not_in"] = "keyword", + ["do"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["fallthrough"] = "keyword", + ["proc"] = "keyword", + ["struct"] = "keyword", + ["union"] = "keyword", + ["enum"] = "keyword", + ["bit_set"] = "keyword", + ["map"] = "keyword", + ["dynamic"] = "keyword", + ["using"] = "keyword", + ["context"] = "keyword", + ["distinct"] = "keyword", + ["asm"] = "keyword", + ["or_break"] = "keyword", + ["or_continue"] = "keyword", + ["or_else"] = "keyword", + ["or_return"] = "keyword", + + -- Builtin procedures and directives + ["cast"] = "keyword2", + ["auto_cast"] = "keyword2", + ["transmute"] = "keyword2", + ["len"] = "keyword2", + ["cap"] = "keyword2", + ["size_of"] = "keyword2", + ["align_of"] = "keyword2", + ["offset_of"] = "keyword2", + ["offset_of_selector"] = "keyword2", + ["offset_of_member"] = "keyword2", + ["offset_of_by_string"] = "keyword2", + ["typeid_of"] = "keyword2", + ["type_of"] = "keyword2", + ["type_info_of"] = "keyword2", + ["type_info_base"] = "keyword2", + ["swizzle"] = "keyword2", + ["complex"] = "keyword2", + ["quaternion"] = "keyword2", + ["real"] = "keyword2", + ["imag"] = "keyword2", + ["jmag"] = "keyword2", + ["kmag"] = "keyword2", + ["conj"] = "keyword2", + ["expand_values"] = "keyword2", + ["min"] = "keyword2", + ["max"] = "keyword2", + ["abs"] = "keyword2", + ["clamp"] = "keyword2", + ["assert"] = "keyword2", + ["soa_zip"] = "keyword2", + ["soa_unzip"] = "keyword2", + ["raw_data"] = "keyword2", + + -- Types + ["rawptr"] = "keyword2", + ["typeid"] = "keyword2", + ["any"] = "keyword2", + ["string"] = "keyword2", + ["cstring"] = "keyword2", + ["int"] = "keyword2", + ["uint"] = "keyword2", + ["uintptr"] = "keyword2", + ["rune"] = "keyword2", + ["byte"] = "keyword2", + ["u8"] = "keyword2", + ["u16"] = "keyword2", + ["u32"] = "keyword2", + ["u64"] = "keyword2", + ["u128"] = "keyword2", + ["i8"] = "keyword2", + ["i16"] = "keyword2", + ["i32"] = "keyword2", + ["i64"] = "keyword2", + ["i128"] = "keyword2", + ["f16"] = "keyword2", + ["f32"] = "keyword2", + ["f64"] = "keyword2", + ["f16le"] = "keyword2", + ["f32le"] = "keyword2", + ["f64le"] = "keyword2", + ["f16be"] = "keyword2", + ["f32be"] = "keyword2", + ["f64be"] = "keyword2", + ["u16le"] = "keyword2", + ["u32le"] = "keyword2", + ["u64le"] = "keyword2", + ["u128le"] = "keyword2", + ["i16le"] = "keyword2", + ["i32le"] = "keyword2", + ["i64le"] = "keyword2", + ["i128le"] = "keyword2", + ["u16be"] = "keyword2", + ["u32be"] = "keyword2", + ["u64be"] = "keyword2", + ["u128be"] = "keyword2", + ["i16be"] = "keyword2", + ["i32be"] = "keyword2", + ["i64be"] = "keyword2", + ["i128be"] = "keyword2", + ["complex32"] = "keyword2", + ["complex64"] = "keyword2", + ["complex128"] = "keyword2", + ["quaternion64"] = "keyword2", + ["quaternion128"] = "keyword2", + ["quaternion256"] = "keyword2", + ["bool"] = "keyword2", + ["b8"] = "keyword2", + ["b16"] = "keyword2", + ["b32"] = "keyword2", + ["b64"] = "keyword2", + ["b128"] = "keyword2", + + -- Literals + ["true"] = "literal", + ["false"] = "literal", + ["nil"] = "literal", + } +} diff --git a/debian/extra/plugins/language_openscad.lua b/debian/extra/plugins/language_openscad.lua new file mode 100644 index 0000000..77c7e37 --- /dev/null +++ b/debian/extra/plugins/language_openscad.lua @@ -0,0 +1,119 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +-- Language Syntax References +-- https://openscad.org/documentation.html#language-reference + +syntax.add { + name = "OpenSCAD", + files = {"%.scad$"}, + comment = "//", + block_comment = { "/*", "*/" }, + patterns = { + { pattern = "//.*", type = "comment" }, -- Single-line comment + { pattern = { "/%*", "%*/" }, type = "comment" }, -- Multi-line comment + { pattern = { '"', '"', '\\' }, type = "string" }, -- String, double quotes + { pattern = { "'", "'", '\\' }, type = "string" }, -- String, apices + { pattern = "-?0x%x+", type = "number" }, -- ? + { pattern = "-?%d+[%d%.eE]*[a-zA-Z]?", type = "number" }, -- ? + { pattern = "-?%.?%d+", type = "number" }, -- ? + { pattern = "[%+%-=/%*%^%%<>!~|&%?%:]", type = "operator" }, -- Operators + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- Functions + { regex = "\\$[a-zA-Z]+", type = "keyword" }, -- Special variables + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + -- ? + ["var"] = "keyword", + ["module"] = "keyword", + ["function"] = "keyword", + ["include"] = "keyword", + ["use"] = "keyword", + -- Constants + ["undef"] = "keyword2", + ["PI"] = "keyword2", + -- 2D + ["circle"] = "keyword", + ["square"] = "keyword", + ["polygon"] = "keyword", + ["text"] = "keyword", + ["import"] = "keyword", + ["projection"] = "keyword", + -- 3D + ["sphere"] = "keyword", + ["cube"] = "keyword", + ["cylinder"] = "keyword", + ["polyhedron"] = "keyword", + ["surface"] = "keyword", + -- Transformations + ["linear_extrude"] = "keyword", + ["rotate_extrude"] = "keyword", + ["translate"] = "keyword", + ["rotate"] = "keyword", + ["scale"] = "keyword", + ["resize"] = "keyword", + ["mirror"] = "keyword", + ["multmatrix"] = "keyword", + ["color"] = "keyword", + ["offset"] = "keyword", + ["hull"] = "keyword", + ["minkowski"] = "keyword", + -- Boolean Operations + ["union"] = "keyword", + ["difference"] = "keyword", + ["intersection"] = "keyword", + -- Flow Control + ["for"] = "keyword", + ["each"] = "keyword", + -- Type Test Functions + ["is_undef"] = "function", + ["is_bool"] = "function", + ["is_num"] = "function", + ["is_string"] = "function", + ["is_list"] = "function", + ["is_function"] = "function", + -- Other + ["echo"] = "keyword", + ["render"] = "keyword", + ["children"] = "keyword", + ["assert"] = "keyword", + -- Functions + ["concat"] = "function", + ["lookup"] = "function", + ["str"] = "function", + ["chr"] = "function", + ["ord"] = "function", + ["search"] = "function", + ["version"] = "function", + ["version_num"] = "function", + ["parent_module"] = "function", + -- Math Functions + ["abs"] = "keyword", + ["sign"] = "keyword", + ["sin"] = "keyword", + ["cos"] = "keyword", + ["tan"] = "keyword", + ["acos"] = "keyword", + ["asin"] = "keyword", + ["atan"] = "keyword", + ["atan2"] = "keyword", + ["floor"] = "keyword", + ["round"] = "keyword", + ["ceil"] = "keyword", + ["ln"] = "keyword", + ["len"] = "keyword", + ["let"] = "keyword", + ["log"] = "keyword", + ["pow"] = "keyword", + ["sqrt"] = "keyword", + ["exp"] = "keyword", + ["rands"] = "keyword", + ["min"] = "keyword", + ["max"] = "keyword", + ["norm"] = "keyword", + ["cross"] = "keyword", + -- Literals + ["true"] = "literal", + ["false"] = "literal", + } +} diff --git a/debian/extra/plugins/language_perl.lua b/debian/extra/plugins/language_perl.lua new file mode 100644 index 0000000..cc1547f --- /dev/null +++ b/debian/extra/plugins/language_perl.lua @@ -0,0 +1,291 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Perl", + files = { "%.pm$", "%.pl$" }, + headers = "^#!.*[ /]perl", + comment = "#", + patterns = { + { pattern = "%#.-\n", type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "qw%(", "%)", '\\' }, type = "string" }, + { pattern = { "qw%[", "%]", '\\' }, type = "string" }, + { pattern = { "qw%/", "%/", '\\' }, type = "string" }, + { pattern = { "qq?%(", "%)", '\\' }, type = "string" }, + { pattern = { "qq?%[", "%]", '\\' }, type = "string" }, + { pattern = { "qq?%/", "%/", '\\' }, type = "string" }, + { pattern = { "^=%w+", "=cut" }, type = "comment" }, + -- until we can get this workign with s///, just don't do any of them. + -- { pattern = { '/', '/', '\\' }, type = "string" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%@%$%*%%]+[%a_][%w_]*", type = "keyword2" }, + { pattern = "[%a_][%w_]*%s+()=>", type = { "string", "operator" } }, + { pattern = "sub%s+()[%w_]+", type = { "keyword", "operator" } }, + { pattern = "[<=>%+%-%*%/:%&%|%!%?%~]+", type = "operator" }, + { pattern = "%--[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["-A"] = "keyword", + ["END"] = "keyword", + ["length"] = "keyword", + ["setpgrp"] = "keyword", + ["-B"] = "keyword", + ["endgrent"] = "keyword", + ["link"] = "keyword", + ["setpriority"] = "keyword", + ["-b"] = "keyword", + ["endhostent"] = "keyword", + ["listen"] = "keyword", + ["setprotoent"] = "keyword", + ["-C"] = "keyword", + ["endnetent"] = "keyword", + ["local"] = "keyword", + ["setpwent"] = "keyword", + ["-c"] = "keyword", + ["endprotoent"] = "keyword", + ["localtime"] = "keyword", + ["setservent"] = "keyword", + ["-d"] = "keyword", + ["endpwent"] = "keyword", + ["log"] = "keyword", + ["setsockopt"] = "keyword", + ["-e"] = "keyword", + ["endservent"] = "keyword", + ["lstat"] = "keyword", + ["shift"] = "keyword", + ["-f"] = "keyword", + ["eof$"] = "keyword", + ["map"] = "keyword", + ["shmctl"] = "keyword", + ["-g"] = "keyword", + ["eval"] = "keyword", + ["mkdir"] = "keyword", + ["shmget"] = "keyword", + ["-k"] = "keyword", + ["exec"] = "keyword", + ["msgctl"] = "keyword", + ["shmread"] = "keyword", + ["-l"] = "keyword", + ["exists"] = "keyword", + ["msgget"] = "keyword", + ["shmwrite"] = "keyword", + ["-M"] = "keyword", + ["exit"] = "keyword", + ["msgrcv"] = "keyword", + ["shutdown"] = "keyword", + ["-O"] = "keyword", + ["fcntl"] = "keyword", + ["msgsnd"] = "keyword", + ["sin"] = "keyword", + ["-o"] = "keyword", + ["fileno"] = "keyword", + ["my"] = "keyword", + ["sleep"] = "keyword", + ["-p"] = "keyword", + ["flock"] = "keyword", + ["next"] = "keyword", + ["socket"] = "keyword", + ["package"] = "keyword", + ["-r"] = "keyword", + ["fork"] = "keyword", + ["not"] = "keyword", + ["socketpair"] = "keyword", + ["-R"] = "keyword", + ["format"] = "keyword", + ["oct"] = "keyword", + ["sort"] = "keyword", + ["-S"] = "keyword", + ["formline"] = "keyword", + ["open"] = "keyword", + ["splice"] = "keyword", + ["-s"] = "keyword", + ["getc"] = "keyword", + ["opendir"] = "keyword", + ["split"] = "keyword", + ["-T"] = "keyword", + ["getgrent"] = "keyword", + ["ord"] = "keyword", + ["sprintf"] = "keyword", + ["-t"] = "keyword", + ["getgrgid"] = "keyword", + ["our"] = "keyword", + ["sqrt"] = "keyword", + ["-u"] = "keyword", + ["getgrnam"] = "keyword", + ["pack"] = "keyword", + ["srand"] = "keyword", + ["-w"] = "keyword", + ["gethostbyaddr"] = "keyword", + ["pipe"] = "keyword", + ["stat"] = "keyword", + ["-W"] = "keyword", + ["gethostbyname"] = "keyword", + ["pop"] = "keyword", + ["state"] = "keyword", + ["-X"] = "keyword", + ["gethostent"] = "keyword", + ["pos"] = "keyword", + ["study"] = "keyword", + ["-x"] = "keyword", + ["getlogin"] = "keyword", + ["print"] = "keyword", + ["substr"] = "keyword", + ["-z"] = "keyword", + ["getnetbyaddr"] = "keyword", + ["printf"] = "keyword", + ["symlink"] = "keyword", + ["abs"] = "keyword", + ["getnetbyname"] = "keyword", + ["prototype"] = "keyword", + ["syscall"] = "keyword", + ["accept"] = "keyword", + ["getnetent"] = "keyword", + ["push"] = "keyword", + ["sysopen"] = "keyword", + ["alarm"] = "keyword", + ["getpeername"] = "keyword", + ["quotemeta"] = "keyword", + ["sysread"] = "keyword", + ["atan2"] = "keyword", + ["getpgrp"] = "keyword", + ["rand"] = "keyword", + ["sysseek"] = "keyword", + ["AUTOLOAD"] = "keyword", + ["getppid"] = "keyword", + ["read"] = "keyword", + ["system"] = "keyword", + ["BEGIN"] = "keyword", + ["getpriority"] = "keyword", + ["readdir"] = "keyword", + ["syswrite"] = "keyword", + ["bind"] = "keyword", + ["getprotobyname"] = "keyword", + ["readline"] = "keyword", + ["tell"] = "keyword", + ["binmode"] = "keyword", + ["getprotobynumber"] = "keyword", + ["SUPER"] = "keyword", + ["readlink"] = "keyword", + ["telldir"] = "keyword", + ["bless"] = "keyword", + ["sub"] = "keyword", + ["getprotoent"] = "keyword", + ["readpipe"] = "keyword", + ["tie"] = "keyword", + ["getpwent"] = "keyword", + ["recv"] = "keyword", + ["tied"] = "keyword", + ["caller"] = "keyword", + ["getpwnam"] = "keyword", + ["redo"] = "keyword", + ["time"] = "keyword", + ["chdir"] = "keyword", + ["getpwuid"] = "keyword", + ["ref"] = "keyword", + ["times"] = "keyword", + ["CHECK"] = "keyword", + ["getservbyname"] = "keyword", + ["rename"] = "keyword", + ["truncate"] = "keyword", + ["chmod"] = "keyword", + ["getservbyport"] = "keyword", + ["require"] = "keyword", + ["uc"] = "keyword", + ["chomp"] = "keyword", + ["getservent"] = "keyword", + ["reset"] = "keyword", + ["ucfirst"] = "keyword", + ["chop"] = "keyword", + ["getsockname"] = "keyword", + ["return"] = "keyword", + ["umask"] = "keyword", + ["chown"] = "keyword", + ["getsockopt"] = "keyword", + ["reverse"] = "keyword", + ["undef"] = "keyword", + ["chr"] = "keyword", + ["glob"] = "keyword", + ["rewinddir"] = "keyword", + ["UNITCHECK"] = "keyword", + ["chroot"] = "keyword", + ["gmtime"] = "keyword", + ["rindex"] = "keyword", + ["unlink"] = "keyword", + ["close"] = "keyword", + ["goto"] = "keyword", + ["rmdir"] = "keyword", + ["unpack"] = "keyword", + ["closedir"] = "keyword", + ["grep"] = "keyword", + ["say"] = "keyword", + ["unshift"] = "keyword", + ["connect"] = "keyword", + ["hex"] = "keyword", + ["scalar"] = "keyword", + ["untie"] = "keyword", + ["cos"] = "keyword", + ["index"] = "keyword", + ["seek"] = "keyword", + ["use"] = "keyword", + ["crypt"] = "keyword", + ["INIT"] = "keyword", + ["seekdir"] = "keyword", + ["utime"] = "keyword", + ["dbmclose"] = "keyword", + ["int"] = "keyword", + ["select"] = "keyword", + ["values"] = "keyword", + ["dbmopen"] = "keyword", + ["ioctl"] = "keyword", + ["semctl"] = "keyword", + ["vec"] = "keyword", + ["defined"] = "keyword", + ["join"] = "keyword", + ["semget"] = "keyword", + ["wait"] = "keyword", + ["delete"] = "keyword", + ["keys"] = "keyword", + ["semop"] = "keyword", + ["waitpid"] = "keyword", + ["DESTROY"] = "keyword", + ["kill"] = "keyword", + ["send"] = "keyword", + ["wantarray"] = "keyword", + ["die"] = "keyword", + ["last"] = "keyword", + ["setgrent"] = "keyword", + ["warn"] = "keyword", + ["dump"] = "keyword", + ["lc"] = "keyword", + ["sethostent"] = "keyword", + ["write"] = "keyword", + ["each"] = "keyword", + ["lcfirst"] = "keyword", + ["setnetent"] = "keyword", + ["while"] = "keyword", + ["for"] = "keyword", + ["if"] = "keyword", + ["else"] = "keyword", + ["elsif"] = "keyword", + ["unless"] = "keyword", + ["no"] = "keyword", + ["new"] = "keyword", + ["do"] = "keyword", + ["__PACKAGE__"] = "keyword", + ["warnings"] = "keyword2", + ["strict"] = "keyword2", + ["eq"] = "operator", + ["ne"] = "operator", + ["lt"] = "operator", + ["gt"] = "operator", + ["le"] = "operator", + ["ge"] = "operator", + ["cmp"] = "operator", + ["STDERR"] = "keyword2", + ["STDOUT"] = "keyword2" + } +} diff --git a/debian/extra/plugins/language_php.lua b/debian/extra/plugins/language_php.lua new file mode 100644 index 0000000..e0dc078 --- /dev/null +++ b/debian/extra/plugins/language_php.lua @@ -0,0 +1,421 @@ +-- mod-version:3 +--[[ + language_php.lua + provides php syntax support allowing mixed html, css and js + version: 20220614_1 +--]] +local syntax = require "core.syntax" +local common = require "core.common" +local config = require "core.config" + +-- load syntax dependencies to add additional rules +require "plugins.language_css" +require "plugins.language_js" + +local psql_found = pcall(require, "plugins.language_psql") +local sql_strings = {} + +config.plugins.language_php = common.merge({ + sql_strings = true, + -- The config specification used by the settings gui + config_spec = { + name = "Language PHP", + { + label = "SQL Strings", + description = "Highlight as SQL, strings starting with sql statements, " + .. "depends on language_psql.", + path = "sql_strings", + type = "toggle", + default = true, + on_apply = function(enabled) + local syntax_php = syntax.get("file.phps") + if enabled and psql_found then + if + not syntax_php.patterns[6].syntax + or + syntax_php.patterns[6].syntax ~= '.sql' + then + table.insert(syntax_php.patterns, 5, sql_strings[1]) + table.insert(syntax_php.patterns, 6, sql_strings[2]) + end + elseif + syntax_php.patterns[6].syntax + and + syntax_php.patterns[6].syntax == '.sql' + then + table.remove(syntax_php.patterns, 5) + table.remove(syntax_php.patterns, 5) + end + end + } + } +}, config.plugins.language_php) + +-- Patterns to match some of the string inline variables +local inline_variables = { + { pattern = "%s+", type = "string" }, + { pattern = "\\%$", type = "string" }, + { pattern = "%{[%$%s]*%}", type = "string" }, + -- matches {$varname[index]} + { pattern = "{" + .. "()%$[%a_][%w_]*" + .. "()%[" + .. "()[%w%s_%-\"\'%(%)|;:,%.#@%%!%^&%*%+=%[%]<>~`%?\\/]*" + .. "()%]" + .. "}", + type = { + "keyword", "keyword2", "keyword", "string", "keyword" + } + }, + { pattern = "{" + .. "()%$[%a_][%w_]*" + .. "()%->" + .. "()[%a_][%w_]*" + .. "()}", + type = { + "keyword", "keyword2", "keyword", "symbol", "keyword" + } + }, + { pattern = "{()%$[%a_][%w_]*()}", + type = { "keyword", "keyword2", "keyword" } + }, + { pattern = "%$[%a_][%w_]*()%[()[%w_]*()%]", + type = { "keyword2", "keyword", "string", "keyword" } + }, + { pattern = "%$[%a_][%w_]*()%->()%a[%w_]*", + type = { "keyword2", "keyword", "symbol" } + }, + { pattern = "%$[%a_][%w_]*", type = "keyword2" }, + { pattern = "%w+", type = "string" } +} + +local function combine_patterns(t1, t2) + local temp = { table.unpack(t1) } + for _, t in ipairs(t2) do + table.insert(temp, t) + end + return temp +end + +local function clone(tbl) + local t = {} + if tbl then + for k, v in pairs(tbl) do + if type(v) == "table" then + t[k] = clone(v) + else + t[k] = v + end + end + end + return t +end + +-- optionally allow sql syntax on strings +if psql_found then + -- generate SQL string marker regex + local sql_markers = { 'create', 'select', 'insert', 'update', 'replace', 'delete', 'drop', 'alter' } + local sql_regex = table.concat(sql_markers, '|') + + -- inject inline variable rules to cloned psql syntax + local syntax_phpsql = clone(syntax.get("file.sql")) + syntax_phpsql.name = "PHP SQL" + syntax_phpsql.files = "%.phpsql$" + table.insert(syntax_phpsql.patterns, 2, { pattern = "\\%$", type = "symbol" }) + table.insert(syntax_phpsql.patterns, 3, { pattern = "%{[%$%s]*%}", type = "symbol" }) + for i=4, 9 do + table.insert(syntax_phpsql.patterns, i, inline_variables[i]) + end + + -- SQL strings + sql_strings = { + { + regex = { '"(?=[\\s(]*(?i:'..sql_regex..')\\s+)', '"', '\\' }, + syntax = syntax_phpsql, + type = "string" + }, + { + regex = { "'(?=[\\s(]*(?i:"..sql_regex..")\\s+)", '\'', '\\' }, + syntax = '.sql', + type = "string" + }, + } +end + +-- define the core php syntax coloring +syntax.add { + name = "PHP Source", + files = { "%.phps$" }, + headers = "^<%?php", + comment = "//", + block_comment = {"/*", "*/"}, + patterns = { + -- Attributes + { pattern = {"#%[", "%]"}, type = "normal" }, + -- Comments + { pattern = "//.-\n", type = "comment" }, + { pattern = "#.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + -- Single quote string + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "<<<'%a%w*'\n", "^%s*%a%w*%f[;]", '\\' }, + type = "string" + }, + -- Strings with support for some inline variables syntax + { pattern = { "<<<%a%w*\n", "^%s*%a%w*%f[;]", '\\' }, + syntax = { + patterns = combine_patterns(inline_variables, { + -- prevent matching outside of the parent string + { pattern = "^%s*%a%w*();$", + type = { "string", "normal" } + }, + { pattern = "%p", type = "string" }, + }), + symbols = {} + }, + type = "string" + }, + { pattern = { '"', '"', '\\' }, + syntax = { + patterns = combine_patterns(inline_variables, { + -- prevent matching outside of the parent string + { pattern = "[^\"]", type = "string" }, + { pattern = "%p+%f[\"]", type = "string" }, + { pattern = "%p", type = "string" }, + }), + symbols = {} + }, + type = "string" + }, + { pattern = { '`', '`', '\\' }, + syntax = { + patterns = combine_patterns(inline_variables, { + -- prevent matching outside of the parent string + { pattern = "[^`]", type = "string" }, + { pattern = "%p+%f[`]", type = "string" }, + { pattern = "%p", type = "string" }, + }), + symbols = {} + }, + type = "string" + }, + { pattern = "0[bB][%d]+", type = "number" }, + { pattern = "0[xX][%da-fA-F]+", type = "number" }, + { pattern = "-?%d[%d_%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "[%.%+%-=/%*%^%%<>!~|&%?:@]", type = "operator" }, + -- Variables + { pattern = "%$[%w_]+", type = "keyword2" }, + -- Respect control structures, treat as keyword not function + { pattern = "if[%s]*%f[(]", type = "keyword" }, + { pattern = "else[%s]*%f[(]", type = "keyword" }, + { pattern = "elseif[%s]*%f[(]", type = "keyword" }, + { pattern = "for[%s]*%f[(]", type = "keyword" }, + { pattern = "foreach[%s]*%f[(]", type = "keyword" }, + { pattern = "while[%s]*%f[(]", type = "keyword" }, + { pattern = "catch[%s]*%f[(]", type = "keyword" }, + { pattern = "switch[%s]*%f[(]", type = "keyword" }, + { pattern = "match[%s]*%f[(]", type = "keyword" }, + { pattern = "fn[%s]*%f[(]", type = "keyword" }, + -- All functions that aren't control structures + { pattern = "[%a_][%w_]*[%s]*%f[(]", type = "function" }, + -- Array type hint not added on symbols to also make it work + -- as a function call + { pattern = "array", type = "literal" }, + -- Match static or namespace container on sub element access + { pattern = "[%a_][%w_]*[%s]*%f[:]", type = "literal" }, + -- Uppercase constants of at least 2 chars in len + { + pattern = "%u[%u_][%u%d_]*%f[%s%+%*%-%.%(%)%?%^%%=/<>~|&;:,!]", + type = "number" + }, + -- Magic constants + { pattern = "__[%u]+__", type = "number" }, + -- Everything else + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["return"] = "keyword", + ["if"] = "keyword", + ["else"] = "keyword", + ["elseif"] = "keyword", + ["endif"] = "keyword", + ["declare"] = "keyword", + ["enddeclare"] = "keyword", + ["switch"] = "keyword", + ["endswitch"] = "keyword", + ["as"] = "keyword", + ["do"] = "keyword", + ["for"] = "keyword", + ["endfor"] = "keyword", + ["foreach"] = "keyword", + ["endforeach"] = "keyword", + ["while"] = "keyword", + ["endwhile"] = "keyword", + ["match"] = "keyword", + ["case"] = "keyword", + ["continue"] = "keyword", + ["default"] = "keyword", + ["break"] = "keyword", + ["goto"] = "keyword", + ["yield"] = "keyword", + + ["try"] = "keyword", + ["catch"] = "keyword", + ["throw"] = "keyword", + ["finally"] = "keyword", + + ["class"] = "keyword", + ["enum"] = "keyword", + ["trait"] = "keyword", + ["interface"] = "keyword", + ["public"] = "keyword", + ["static"] = "keyword", + ["protected"] = "keyword", + ["private"] = "keyword", + ["readonly"] = "keyword", + ["abstract"] = "keyword", + ["final"] = "keyword", + ["$this"] = "literal", + + ["function"] = "keyword", + ["fn"] = "keyword", + ["global"] = "keyword", + ["var"] = "keyword", + ["const"] = "keyword", + + ["bool"] = "literal", + ["boolean"] = "literal", + ["int"] = "literal", + ["integer"] = "literal", + ["real"] = "literal", + ["double"] = "literal", + ["float"] = "literal", + ["string"] = "literal", + ["object"] = "literal", + ["callable"] = "literal", + ["iterable"] = "literal", + ["void"] = "literal", + ["parent"] = "literal", + ["self"] = "literal", + ["mixed"] = "literal", + ["never"] = "literal", + + ["namespace"] = "keyword", + ["extends"] = "keyword", + ["implements"] = "keyword", + ["instanceof"] = "keyword", + ["require"] = "keyword", + ["require_once"] = "keyword", + ["include"] = "keyword", + ["include_once"] = "keyword", + ["use"] = "keyword", + ["new"] = "keyword", + ["clone"] = "keyword", + + ["true"] = "number", + ["false"] = "number", + ["NULL"] = "number", + ["null"] = "number", + + ["print"] = "function", + ["echo"] = "function", + ["exit"] = "function", + }, +} + +-- insert sql string rules after the "/%*", "%*/" pattern +if psql_found and config.plugins.language_php.sql_strings then + local syntax_php = syntax.get("file.phps") + table.insert(syntax_php.patterns, 5, sql_strings[1]) + table.insert(syntax_php.patterns, 6, sql_strings[2]) +end + +-- allows html, css and js coloring on php files +syntax.add { + name = "PHP", + files = { "%.php$", "%.phtml" }, + block_comment = { "" }, + patterns = { + { + regex = { + "<\\?php\\s+", + "(?:\\?>|(?=`{3}))" -- end if inside markdown code tags + }, + syntax = ".phps", + type = "keyword2" + }, + { + pattern = { + "<%?=?", + "%?>" + }, + syntax = ".phps", + type = "keyword2" + }, + { + pattern = { + "<%s*[sS][cC][rR][iI][pP][tT]%f[%s>].->", + "<%s*/%s*[sS][cC][rR][iI][pP][tT]%s*>" + }, + syntax = ".js", + type = "function" + }, + { + pattern = { + "<%s*[sS][tT][yY][lL][eE]%f[%s>].->", + "<%s*/%s*[sS][tT][yY][lL][eE]%s*>" + }, + syntax = ".css", + type = "function" + }, + { pattern = { "" }, type = "comment" }, + { pattern = { '%f[^>][^<]', '%f[<]' }, type = "normal" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "%f[^<]![%a_][%w_]*", type = "keyword2" }, + { pattern = "%f[^<][%a_][%w_]*", type = "function" }, + { pattern = "%f[^<]/[%a_][%w_]*", type = "function" }, + { pattern = "[%a_][%w_]*", type = "keyword" }, + { pattern = "[/<>=]", type = "operator" }, + -- match markdown code tags to be able to end php highlighting + -- when inside the subsyntax .phps + { regex = "(?=`{3})", type = "string" } + }, + symbols = {}, +} + +-- allow coloring of php code inside css and js code +local syntaxes = { "css", "js" } +for _, ext in pairs(syntaxes) do + local syntax_table = syntax.get("file."..ext, "") + + table.insert( + syntax_table.patterns, + 1, + { + pattern = { + "<%?=?", + "%?>" + }, + syntax = ".phps", + type = "keyword2" + } + ) + + table.insert( + syntax_table.patterns, + 1, + { + pattern = { + "<%?php%s+", + "%?>" + }, + syntax = ".phps", + type = "keyword2" + } + ) +end diff --git a/debian/extra/plugins/language_pico8.lua b/debian/extra/plugins/language_pico8.lua new file mode 100644 index 0000000..aefd6f6 --- /dev/null +++ b/debian/extra/plugins/language_pico8.lua @@ -0,0 +1,53 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "PICO-8", + files = "%.p8$", + headers = "^pico-8 cartridge", + comment = "--", + patterns = { + { pattern = { 'pico%-8 cartridge', '__lua__' }, type = "comment" }, + { pattern = { '__gfx__\n', '%z' }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "%[%[", "%]%]" }, type = "string" }, + { pattern = { "%-%-%[%[", "%]%]"}, type = "comment" }, + { pattern = "%-%-.-\n", type = "comment" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "%.%.%.?", type = "operator" }, + { pattern = "[<>~=&|]=", type = "operator" }, + { pattern = "[%+%-=/%*%^%%#<>]", type = "operator" }, + { pattern = "[%a_][%w_]*%s*%f[(\"{]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "::[%a_][%w_]*::", type = "function" }, + }, + symbols = { + ["if"] = "keyword", + ["then"] = "keyword", + ["else"] = "keyword", + ["elseif"] = "keyword", + ["end"] = "keyword", + ["do"] = "keyword", + ["function"] = "keyword", + ["repeat"] = "keyword", + ["until"] = "keyword", + ["while"] = "keyword", + ["for"] = "keyword", + ["break"] = "keyword", + ["return"] = "keyword", + ["local"] = "keyword", + ["in"] = "keyword", + ["not"] = "keyword", + ["and"] = "keyword", + ["or"] = "keyword", + ["goto"] = "keyword", + ["self"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + ["nil"] = "literal", + }, +} + diff --git a/debian/extra/plugins/language_pkgbuild.lua b/debian/extra/plugins/language_pkgbuild.lua new file mode 100644 index 0000000..5c6a3c5 --- /dev/null +++ b/debian/extra/plugins/language_pkgbuild.lua @@ -0,0 +1,251 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "PKGBUILD", + files = { PATHSEP .. "PKGBUILD$" }, + comment = "#", + patterns = { + -- Don't colorize number of arguments expression as comment + { pattern = "%$#", type = "keyword2" }, + { pattern = "#.*", type = "comment" }, + -- Strings + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { '`', '`', '\\' }, type = "string" }, + -- Ignore numbers that start with dots or slashes + { pattern = "%f[%w_%.%/]%d[%d%.]*%f[^%w_%.]", type = "number" }, + -- Custom keyword matches + { pattern = "source%f[=]", type = "literal" }, + { pattern = "[ \t]source ", type = "keyword" }, + { pattern = "install%f[=]", type = "literal" }, + { pattern = "[ \t]tar ", type = "keyword" }, + { pattern = "[ \t]install ", type = "keyword" }, + { pattern = "[ \t]arch%-meson ", type = "keyword" }, + { pattern = "[ \t]patch ", type = "keyword" }, + { pattern = "[ \t]git ", type = "keyword" }, + { pattern = "[ \t]svn ", type = "keyword" }, + { pattern = "[ \t]fossil ", type = "keyword" }, + { pattern = "[ \t]meson ", type = "keyword" }, + { pattern = "[ \t]ninja ", type = "keyword" }, + { pattern = "[ \t]cmake ", type = "keyword" }, + { pattern = "[ \t]waf ", type = "keyword" }, + { pattern = "[ \t]%./configure[%s%c]+", type = "keyword" }, + -- Operators + { pattern = "[!<>|&%[%]:=*]", type = "operator" }, + -- Match parameters + { pattern = "%f[%S][%+%-][%w%-_:]+", type = "function" }, + { pattern = "%f[%S][%+%-][%w%-_]+%f[=]", type = "function" }, + -- Prevent parameters with assignments from been matched as variables + { + pattern = "%s%-%a[%w_%-]*%s+()%d[%d%.]+", + type = { "function", "number" } + }, + { + pattern = "%s%-%a[%w_%-]*%s+()%a[%a%-_:=]+", + type = { "function", "symbol" } + }, + -- Match variable assignments + { pattern = "[_%a][%w_]+%f[%+=]", type = "keyword2" }, + -- Match variable expansions + { pattern = "%${.-}", type = "keyword2" }, + { pattern = "%$[%d%$%a_@*][%w_]*", type = "keyword2" }, + -- Functions + { pattern = "[%a_%-][%w_%-]*[%s]*%f[(]", type = "function" }, + -- Everything else + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + -- Bash keywords + ["true"] = "literal", + ["false"] = "literal", + ["case"] = "keyword", + ["in"] = "keyword", + ["esac"] = "keyword", + ["if"] = "keyword", + ["then"] = "keyword", + ["elif"] = "keyword", + ["else"] = "keyword", + ["fi"] = "keyword", + ["until"] = "keyword", + ["while"] = "keyword", + ["do"] = "keyword", + ["done"] = "keyword", + ["for"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["shift"] = "keyword", + ["function"] = "keyword", + ["local"] = "keyword", + ["echo"] = "keyword", + ["return"] = "keyword", + ["exit"] = "keyword", + ["alias"] = "keyword", + ["test"] = "keyword", + ["select"] = "keyword", + ["type"] = "keyword", + ["declare"] = "keyword", + ["set"] = "keyword", + ["unalias"] = "keyword", + ["unset"] = "keyword", + ["enable"] = "keyword", + ["eval"] = "keyword", + ["exec"] = "keyword", + ["export"] = "keyword", + ["getopts"] = "keyword", + ["hash"] = "keyword", + ["history"] = "keyword", + ["help"] = "keyword", + ["jobs"] = "keyword", + ["kill"] = "keyword", + ["let"] = "keyword", + ["mapfile"] = "keyword", + ["readarray"] = "keyword", + -- Commands + ["printf"] = "keyword", + ["read"] = "keyword", + ["pwd"] = "keyword", + ["time"] = "keyword", + ["cd"] = "keyword", + ["cp"] = "keyword", + ["mv"] = "keyword", + ["mkdir"] = "keyword", + ["rm"] = "keyword", + ["rmdir"] = "keyword", + ["chown"] = "keyword", + ["chmod"] = "keyword", + ["touch"] = "keyword", + ["ln"] = "keyword", + ["cat"] = "keyword", + ["sed"] = "keyword", + ["awk"] = "keyword", + ["find"] = "keyword", + ["grep"] = "keyword", + ["head"] = "keyword", + ["less"] = "keyword", + ["gcc"] = "keyword", + ["gpp"] = "keyword", + ["make"] = "keyword", + ["qmake"] = "keyword", + -- PKGBUILD keywords + ["pkgbase"] = "literal", + ["pkgname"] = "literal", + ["pkgver"] = "literal", + ["pkgrel"] = "literal", + ["epoch"] = "literal", + ["pkgdesc"] = "literal", + ["arch"] = "literal", + ["url"] = "literal", + ["license"] = "literal", + ["groups"] = "literal", + ["depends"] = "literal", + ["depends_arm"] = "literal", + ["depends_armv6h"] = "literal", + ["depends_armv7h"] = "literal", + ["depends_aarch64"] = "literal", + ["depends_i686"] = "literal", + ["depends_x86_64"] = "literal", + ["makedepends"] = "literal", + ["makedepends_arm"] = "literal", + ["makedepends_armv6h"] = "literal", + ["makedepends_armv7h"] = "literal", + ["makedepends_aarch64"] = "literal", + ["makedepends_i686"] = "literal", + ["makedepends_x86_64"] = "literal", + ["checkdepends"] = "literal", + ["checkdepends_arm"] = "literal", + ["checkdepends_armv6h"] = "literal", + ["checkdepends_armv7h"] = "literal", + ["checkdepends_aarch64"] = "literal", + ["checkdepends_i686"] = "literal", + ["checkdepends_x86_64"] = "literal", + ["optdepends"] = "literal", + ["optdepends_arm"] = "literal", + ["optdepends_armv6h"] = "literal", + ["optdepends_armv7h"] = "literal", + ["optdepends_aarch64"] = "literal", + ["optdepends_i686"] = "literal", + ["optdepends_x86_64"] = "literal", + ["provides"] = "literal", + ["provides_arm"] = "literal", + ["provides_armv6h"] = "literal", + ["provides_armv7h"] = "literal", + ["provides_aarch64"] = "literal", + ["provides_i686"] = "literal", + ["provides_x86_64"] = "literal", + ["conflicts"] = "literal", + ["conflicts_arm"] = "literal", + ["conflicts_armv6h"] = "literal", + ["conflicts_armv7h"] = "literal", + ["conflicts_aarch64"] = "literal", + ["conflicts_i686"] = "literal", + ["conflicts_x86_64"] = "literal", + ["replaces"] = "literal", + ["replaces_arm"] = "literal", + ["replaces_armv6h"] = "literal", + ["replaces_armv7h"] = "literal", + ["replaces_aarch64"] = "literal", + ["replaces_i686"] = "literal", + ["replaces_x86_64"] = "literal", + ["backup"] = "literal", + ["options"] = "literal", + ["changelog"] = "literal", + ["source_arm"] = "literal", + ["source_armv6h"] = "literal", + ["source_armv7h"] = "literal", + ["source_aarch64"] = "literal", + ["source_i686"] = "literal", + ["source_x86_64"] = "literal", + ["noextract"] = "literal", + ["validpgpkeys"] = "literal", + ["md5sums"] = "literal", + ["md5sums_arm"] = "literal", + ["md5sums_armv6h"] = "literal", + ["md5sums_armv7h"] = "literal", + ["md5sums_aarch64"] = "literal", + ["md5sums_i686"] = "literal", + ["md5sums_x86_64"] = "literal", + ["sha1sums"] = "literal", + ["sha1sums_arm"] = "literal", + ["sha1sums_armv6h"] = "literal", + ["sha1sums_armv7h"] = "literal", + ["sha1sums_aarch64"] = "literal", + ["sha1sums_i686"] = "literal", + ["sha1sums_x86_64"] = "literal", + ["sha256sums"] = "literal", + ["sha256sums_arm"] = "literal", + ["sha256sums_armv6h"] = "literal", + ["sha256sums_armv7h"] = "literal", + ["sha256sums_aarch64"] = "literal", + ["sha256sums_i686"] = "literal", + ["sha256sums_x86_64"] = "literal", + ["sha224sums"] = "literal", + ["sha224sums_arm"] = "literal", + ["sha224sums_armv6h"] = "literal", + ["sha224sums_armv7h"] = "literal", + ["sha224sums_aarch64"] = "literal", + ["sha224sums_i686"] = "literal", + ["sha224sums_x86_64"] = "literal", + ["sha384sums"] = "literal", + ["sha384sums_arm"] = "literal", + ["sha384sums_armv6h"] = "literal", + ["sha384sums_armv7h"] = "literal", + ["sha384sums_aarch64"] = "literal", + ["sha384sums_i686"] = "literal", + ["sha384sums_x86_64"] = "literal", + ["sha512sums"] = "literal", + ["sha512sums_arm"] = "literal", + ["sha512sums_armv6h"] = "literal", + ["sha512sums_armv7h"] = "literal", + ["sha512sums_aarch64"] = "literal", + ["sha512sums_i686"] = "literal", + ["sha512sums_x86_64"] = "literal", + ["b2sums"] = "literal", + ["b2sums_arm"] = "literal", + ["b2sums_armv6h"] = "literal", + ["b2sums_armv7h"] = "literal", + ["b2sums_aarch64"] = "literal", + ["b2sums_i686"] = "literal", + ["b2sums_x86_64"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_po.lua b/debian/extra/plugins/language_po.lua new file mode 100644 index 0000000..a1b098c --- /dev/null +++ b/debian/extra/plugins/language_po.lua @@ -0,0 +1,21 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "PO", + files = { "%.po$", "%.pot$" }, + comment = "#", + patterns = { + { pattern = { "#", "\n"}, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = "[%[%]]", type = "operator" }, + { pattern = "%d+", type = "number" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["msgctxt"] = "keyword", + ["msgid"] = "keyword", + ["msgid_plural"] = "keyword", + ["msgstr"] = "keyword", + }, +} diff --git a/debian/extra/plugins/language_powershell.lua b/debian/extra/plugins/language_powershell.lua new file mode 100644 index 0000000..fdba844 --- /dev/null +++ b/debian/extra/plugins/language_powershell.lua @@ -0,0 +1,77 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "PowerShell", + files = { + "%.ps1$", "%.psm1$", "%.psd1$", "%.ps1xml$", + "%.pssc$", "%.psrc$", "%.cdxml$" + }, + comment = "#", + patterns = { + {pattern = "#.*\n", type = "comment"}, + {pattern = [[\.]], type = "normal"}, + {pattern = {'"', '"'}, type = "string"}, + {pattern = {"'", "'"}, type = "string"}, + {pattern = "%f[%w_][%d%.]+%f[^%w_]", type = "number"}, + {pattern = "[%+=/%*%^%%<>!~|&,:]+", type = "operator"}, + {pattern = "%f[%S]%-[%w%-_]+", type = "function"}, + {pattern = "[%u][%a]+[%-][%u][%a]+", type = "function"}, + {pattern = "${.*}", type = "symbol"}, + {pattern = "$[%a_@*][%w_]*", type = "keyword2"}, + {pattern = "$[%$][%a]+", type = "keyword2"}, + {pattern = "[%a_][%w_]*", type = "symbol"} + }, + symbols = { + ["if"] = "keyword", + ["else"] = "keyword", + ["elseif"] = "keyword", + ["switch"] = "keyword", + ["default"] = "keyword", + ["function"] = "keyword", + ["filter"] = "keyword", + ["workflow"] = "keyword", + ["configuration"] = "keyword", + ["class"] = "keyword", + ["enum"] = "keyword", + ["Parameter"] = "keyword", + ["ValidateScript"] = "keyword", + ["CmdletBinding"] = "keyword", + ["try"] = "keyword", + ["catch"] = "keyword", + ["finally"] = "keyword", + ["throw"] = "keyword", + ["while"] = "keyword", + ["for"] = "keyword", + ["do"] = "keyword", + ["until"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["foreach"] = "keyword", + ["in"] = "keyword", + ["return"] = "keyword", + ["where"] = "function", + ["select"] = "function", + ["filter"] = "keyword", + ["in"] = "keyword", + ["trap"] = "keyword", + ["param"] = "keyword", + ["data"] = "keyword", + ["dynamicparam"] = "keyword", + ["begin"] = "function", + ["process"] = "function", + ["end"] = "function", + ["exit"] = "function", + ["inlinescript"] = "function", + ["parallel"] = "function", + ["sequence"] = "function", + ["true"] = "literal", + ["false"] = "literal", + ["TODO"] = "comment", + ["FIXME"] = "comment", + ["XXX"] = "comment", + ["TBD"] = "comment", + ["HACK"] = "comment", + ["NOTE"] = "comment" + } +} diff --git a/debian/extra/plugins/language_psql.lua b/debian/extra/plugins/language_psql.lua new file mode 100644 index 0000000..afb5a11 --- /dev/null +++ b/debian/extra/plugins/language_psql.lua @@ -0,0 +1,92 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +-- In sql symbols can be lower case and upper case +local keywords = { + "CREATE", "SELECT", "ADD", "INSERT", "INTO", "UPDATE", + "DELETE", "TABLE", "DROP", "VALUES", "NOT", + "NULL", "PRIMARY", "KEY", "REFERENCES", + "DEFAULT", "UNIQUE", "CONSTRAINT", "CHECK", + "ON", "EXCLUDE", "WITH", "USING", "WHERE", + "GROUP", "BY", "HAVING", "DISTINCT", "LIMIT", + "OFFSET", "ONLY", "CROSS", "JOIN", "INNER", + "LEFT", "RIGHT", "FULL", "OUTER", "NATURAL", + "AND", "OR", "AS", "ORDER", "ORDINALITY", + "UNNEST", "FROM", "VIEW", "RETURNS", "SETOF", + "LANGUAGE", "SQL", "LIKE", "LATERAL", + "INTERVAL", "PARTITION", "UNION", "INTERSECT", + "EXCEPT", "ALL", "ASC", "DESC", "NULLS", + "FIRST", "LAST", "IN", "RECURSIVE", "ARRAY", + "RETURNING", "SET", "ALSO", "INSTEAD", + "ALTER", "SEQUENCE", "OWNED", "AT", "ZONE", + "WITHOUT", "TO", "TIMEZONE", "TYPE", "ENUM", + "DOCUMENT", "XMLPARSE", "XMLSERIALIZE", + "CONTENT", "OPTION", "INDEX", "ANY", + "EXTENSION", "ISNULL", "NOTNULL", "UNKNOWN", + "CASE", "THEN", "WHEN", "ELSE", "END", + "ROWS", "BETWEEN", "UNBOUNDED", "PRECEDING", + "UNBOUNDED", "FOLLOWING", "EXISTS", "SOME", + "COLLATION", "FOR", "TRIGGER", "BEFORE", + "EACH", "ROW", "EXECUTE", "PROCEDURE", + "FUNCTION", "DECLARE", "BEGIN", "LOOP", + "RAISE", "NOTICE", "LOOP", "EVENT", + "OPERATOR", "DOMAIN", "VARIADIC", "FOREIGN" +} + +local types = { + "BIGINT", "INT8", "BIGSERIAL", "SERIAL8", + "BIT", "VARBIT", "BOOLEAN", "BOOL", "BOX", + "BYTEA", "CHARACTER", "CHAR", "VARCHAR", + "CIDR", "CIRCLE", "DATE", "DOUBLE", + "PRECISION", "FLOAT8", "INET", "INTEGER", + "INT", "INT4", "INTERVAL", "JSON", "JSONB", + "LINE", "LSEG", "MACADDR", "MONEY", "NUMERIC", + "DECIMAL", "PATH", "POINT", "POLYGON", "REAL", + "FLOAT4", "INT2", "SMALLINT", "SMALLSERIAL", + "SERIAL2", "SERIAL", "SERIAL4", "TEXT", + "TIME", "TIMEZ", "TIMESTAMP", "TIMESTAMPZ", + "TSQUERY", "TSVECTOR", "TXID_SNAPSHOT", + "UUID", "XML", "INT4RANGE", "INT8RANGE", + "NUMRANGE", "TSRANGE", "TSTZRANGE", + "DATERANGE", "PG_LSN" +} + +local literals = { + "FALSE", "TRUE", "CURRENT_TIMESTAMP", + "CURRENT_TIME", "CURRENT_DATE", "LOCALTIME", + "LOCALTIMESTAMP" +} + +local symbols = {} +for _, keyword in ipairs(keywords) do + symbols[keyword:lower()] = "keyword" + symbols[keyword] = "keyword" +end + +for _, type in ipairs(types) do + symbols[type:lower()] = "keyword2" + symbols[type] = "keyword2" +end + +for _, literal in ipairs(literals) do + symbols[literal:lower()] = "literal" + symbols[literal] = "literal" +end + +syntax.add { + name = "PostgreSQL", + files = { "%.sql$", "%.psql$" }, + comment = "--", + patterns = { + { pattern = "%-%-.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%%<>!~|&@%?$#]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = symbols, +} + diff --git a/debian/extra/plugins/language_rescript.lua b/debian/extra/plugins/language_rescript.lua new file mode 100644 index 0000000..3d3bca0 --- /dev/null +++ b/debian/extra/plugins/language_rescript.lua @@ -0,0 +1,60 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "ReScript", + files = { "%.res$" }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "`", "`", '\\' }, type = "string" }, + { pattern = "#[%a_][%w_]*", type = "literal" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "%f[^%.>]%l[%w_]*", type = "function" }, + { pattern = "%l[%w_]*%f[(]", type = "function" }, + { pattern = "%u[%w_]*", type = "keyword2" }, + { pattern = "[%l_][%w_%.]*", type = "symbol" }, + { pattern = "@%l[%w_]*", type = "string" }, + }, + symbols = { + ["and"] = "keyword", + ["array"] = "keyword2", + ["as"] = "keyword", + ["assert"] = "keyword", + ["bool"] = "keyword2", + ["constraint"] = "keyword", + ["downto"] = "keyword", + ["else"] = "keyword", + ["exception"] = "keyword", + ["external"] = "keyword", + ["false"] = "literal", + ["for"] = "keyword", + ["if"] = "keyword", + ["in"] = "keyword", + ["int"] = "keyword2", + ["include"] = "keyword", + ["lazy"] = "keyword", + ["let"] = "keyword", + ["module"] = "keyword", + ["mutable"] = "keyword", + ["of"] = "keyword", + ["open"] = "keyword", + ["option"] = "keyword2", + ["rec"] = "keyword", + ["switch"] = "keyword", + ["string"] = "keyword2", + ["to"] = "keyword", + ["true"] = "literal", + ["try"] = "keyword", + ["type"] = "keyword", + ["when"] = "keyword", + ["while"] = "keyword", + ["with"] = "keyword", + } +} diff --git a/debian/extra/plugins/language_ring.lua b/debian/extra/plugins/language_ring.lua new file mode 100644 index 0000000..ca9123b --- /dev/null +++ b/debian/extra/plugins/language_ring.lua @@ -0,0 +1,92 @@ +-- mod-version:3 +-- Refrence: https://ring-lang.github.io/doc1.21.2/syntaxflexibility.html + +local syntax = require "core.syntax" + +-- Keywords +local keywords = { + "enablehashcomments", "disablehashcomments", "call", "class", "from", "get", "give", + "import", "load", "new", "package", "private", "changeringkeyword", "changeringoperator", + "loadsyntax", "endclass", "endpackage", "if", "but", "else", "elseif", "ok", "for", + "foreach", "to", "next", "catch", "step", "endfor", "while", "other", "end", "do", + "endwhile", "endswitch", "endtry", "try", "break", "bye", "continue", "default", + "endfunc", "endfunction", "return", "switch", "case", "on", "off", "again", "exit", + "loop", "done", "in", "func", "def", "nl" +} + +-- Types using ring type hints library +local types = { + "char", "unsigned", "signed", "int", "short", "long", "float", "double", "void", + "byte", "boolean", "string", "list", "number", "object", "public", "static", + "abstract", "protected", "override" +} + +-- Special values +local literals = { + "true", "false", "null" +} + +-- Built-in functions +local builtin_functions = { + "see", "put", "print" +} + +local symbols = {} + +for _, keyword in ipairs(keywords) do + symbols[keyword:upper()] = "keyword" + symbols[keyword:gsub("^%l", string.upper)] = "keyword" + symbols[keyword] = "keyword" +end + +for _, type in ipairs(types) do + symbols[type:upper()] = "keyword2" + symbols[type:gsub("^%l", string.upper)] = "keyword2" + symbols[type] = "keyword2" +end + +for _, literal in ipairs(literals) do + symbols[literal:upper()] = "literal" + symbols[literal:gsub("^%l", string.upper)] = "literal" + symbols[literal] = "literal" +end + +for _, func in ipairs(builtin_functions) do + symbols[func:upper()] = "function" + symbols[func:gsub("^%l", string.upper)] = "function" + symbols[func] = "function" +end + +local string_syntax = { + patterns = { + { pattern = {"%#{", "}", "\\"}, type="keyword", syntax = ".ring" }, + { pattern = "[^#\"`']+", type = "string"}, + { pattern = "[#\"`']", type = "string"} + }, + symbols = {} +} + +syntax.add { + name = "Ring", + files = { "%.ring$", "%.rh$", "%.rform$" }, + comment = "//", + patterns = { + { pattern = "#.*", type = "comment" }, + { pattern = "//.*", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string", syntax = string_syntax }, + { pattern = { "'", "'", '\\' }, type = "string", syntax = string_syntax }, + { pattern = { "`", "`", '\\' }, type = "string", syntax = string_syntax }, + { pattern = "-?%d+[%d%.]*f?", type = "number" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[Dd][Ee][Ff]()%s+()[%a_][%w_]*", type = { "keyword", "normal", "function" } }, + { pattern = "[Ff][Uu][Nn][Cc]()%s+()[%a_][%w_]*", type = { "keyword", "normal", "function" } }, + { pattern = "[Cc][Ll][Aa][Ss][Ss]()%s+()[%a_][%w_]*", type = { "keyword", "normal", "function" } }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "%?", type = "keyword" }, + { pattern = ":[%a_][%w_]*", type = "literal" }, + }, + symbols = symbols +} diff --git a/debian/extra/plugins/language_rivet.lua b/debian/extra/plugins/language_rivet.lua new file mode 100644 index 0000000..7db2db2 --- /dev/null +++ b/debian/extra/plugins/language_rivet.lua @@ -0,0 +1,102 @@ +-- mod-version:3 + +-- Syntax highlighting for the Rivet programming language. +-- This plugin is always updated to the latest Rivet syntax. +-- By StunxFS =). + +local syntax = require "core.syntax" + +syntax.add { + name = "Rivet", + files = {"%.ri$"}, + comment = "//", + block_comment = {"/*", "*/"}, + patterns = { + {pattern = "//.*", type = "comment"}, + {pattern = {"/%*", "%*/"}, type = "comment"}, + {pattern = {'[bcr]?"', '"', "\\"}, type = "string"}, + {pattern = {"[b]?'", "'", "\\"}, type = "string"}, + {pattern = "0b[01_]+", type = "number"}, + {pattern = "0o[0-7_]+", type = "number"}, + {pattern = "0x[%x_]+", type = "number"}, + {pattern = "%d[%d_]*%.[%d_]*[eE][-+]?%d+", type = "number"}, + {pattern = "%d[%d_]*%.[%d_]*", type = "number"}, + {pattern = "%d[%d_]*", type = "number"}, + {pattern = "-?%.?%d+", type = "number"}, + {pattern = "[%[%]%(%)%+%-=/%*%^%%<>!~|&%.%?:;]", type = "operator"}, + { + pattern = "_?%u[%u_][%u%d_]*%f[%s%+%*%-%.%)%]}%?%^%%=/<>~|&;:,!]", + type = "literal" + }, + -- types + {pattern = "[A-Z][%w_]*", type = "keyword2"}, + -- builtin func/var + {pattern = "%@%s?[%a_][%w_]*", type = "literal"}, + -- `defer` modes + {pattern = "defer%s?%(%s?()[%a_][%w_]*()%s?%)", type = {"keyword", "comment", "normal"} }, + -- functions + {pattern = "[%a_][%w_]*%f[(]", type = "function"}, + -- attributes + {pattern = "#%s?%[.*%]", type = "keyword2"}, + -- symbols + {pattern = "[%a_][%w_]*", type = "symbol"} + }, + symbols = { + ["alias"] = "keyword", + ["as"] = "keyword", + ["break"] = "keyword", + ["catch"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["defer"] = "keyword", + ["else"] = "keyword", + ["enum"] = "keyword", + ["extend"] = "keyword", + ["extern"] = "keyword", + ["func"] = "keyword", + ["for"] = "keyword", + ["if"] = "keyword", + ["import"] = "keyword", + ["in"] = "keyword", + ["is"] = "keyword", + ["match"] = "keyword", + ["mut"] = "keyword", + ["pub"] = "keyword", + ["return"] = "keyword", + ["struct"] = "keyword", + ["test"] = "keyword", + ["throw"] = "keyword", + ["trait"] = "keyword", + ["unsafe"] = "keyword", + ["var"] = "keyword", + ["while"] = "keyword", + + -- literals + ["false"] = "literal", + ["none"] = "literal", + ["self"] = "literal", + ["true"] = "literal", + + -- types + ["never"] = "keyword2", + ["bool"] = "keyword2", + ["comptime_int"] = "keyword2", + ["comptime_float"] = "keyword2", + ["int"] = "keyword2", + ["int8"] = "keyword2", + ["int16"] = "keyword2", + ["int32"] = "keyword2", + ["int64"] = "keyword2", + ["uint"] = "keyword2", + ["uint8"] = "keyword2", + ["uint16"] = "keyword2", + ["uint32"] = "keyword2", + ["uint64"] = "keyword2", + ["float32"] = "keyword2", + ["float64"] = "keyword2", + ["rawptr"] = "keyword2", + ["rune"] = "keyword2", + ["string"] = "keyword2", + ["Self"] = "keyword2" + } +} diff --git a/debian/extra/plugins/language_ruby.lua b/debian/extra/plugins/language_ruby.lua new file mode 100644 index 0000000..e106629 --- /dev/null +++ b/debian/extra/plugins/language_ruby.lua @@ -0,0 +1,73 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Ruby", + files = { "%.rb$", PATHSEP .. "%.gemspec$", PATHSEP .. "Gemfile$", PATHSEP .. "Gemfile%.lock$" }, + headers = "^#!.*[ /]ruby", + comment = "#", + patterns = { + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "%#.-\n", type = "comment" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "@?@[%a_][%w_]*", type = "keyword2" }, + { pattern = "::[%w_]*", type = "symbol" }, + { pattern = ":[%w_]*", type = "keyword2" }, + { pattern = "[%a_][%w_]*:[^:]", type = "keyword2" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["nil"] = "literal", + ["true"] = "literal", + ["false"] = "literal", + ["private"] = "keyword", + ["extend"] = "keyword", + ["include"] = "keyword", + ["require"] = "keyword", + ["require_dependency"] = "keyword", + ["__ENCODING__"] = "keyword", + ["__LINE__"] = "keyword", + ["__FILE__"] = "keyword", + ["BEGIN"] = "keyword", + ["END"] = "keyword", + ["alias"] = "keyword", + ["and"] = "keyword", + ["begin"] = "keyword", + ["break"] = "keyword", + ["case"] = "keyword", + ["class"] = "keyword", + ["def"] = "keyword", + ["defined?"] = "keyword", + ["do"] = "keyword", + ["else"] = "keyword", + ["elsif"] = "keyword", + ["end"] = "keyword", + ["ensure"] = "keyword", + ["for"] = "keyword", + ["if"] = "keyword", + ["in"] = "keyword", + ["module"] = "keyword", + ["next"] = "keyword", + ["not"] = "keyword", + ["or"] = "keyword", + ["redo"] = "keyword", + ["rescue"] = "keyword", + ["retry"] = "keyword", + ["return"] = "keyword", + ["self"] = "keyword", + ["super"] = "keyword", + ["then"] = "keyword", + ["undef"] = "keyword", + ["unless"] = "keyword", + ["until"] = "keyword", + ["when"] = "keyword", + ["while"] = "keyword", + ["yield"] = "keyword" + }, +} + diff --git a/debian/extra/plugins/language_rust.lua b/debian/extra/plugins/language_rust.lua new file mode 100644 index 0000000..09e75ba --- /dev/null +++ b/debian/extra/plugins/language_rust.lua @@ -0,0 +1,89 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Rust", + files = { "%.rs$" }, + comment = "//", + block_comment = { "/*", "*/" }, + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { 'r#"', '"#', '\\' }, type = "string" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = "'.'", type = "string" }, + { pattern = "'[%a_][%a%d_]*", type = "keyword2" }, + { pattern = "0[oO_][0-7]+", type = "number" }, + { pattern = "-?0x[%x_]+", type = "number" }, + { pattern = "-?%d+_%d", type = "number" }, + { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, + { pattern = "-?%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { regex = "[[:alpha:]_][\\w]*(?=\\s*<[\\w\\s,']+>\\s*\\()", type = "function" }, + { pattern = "[%a_][%w_]*!%f[%[(]", type = "function" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["as"] = "keyword", + ["async"] = "keyword", + ["await"] = "keyword", + ["break"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["crate"] = "keyword", + ["dyn"] = "keyword", + ["else"] = "keyword", + ["enum"] = "keyword", + ["extern"] = "keyword", + ["fn"] = "keyword", + ["for"] = "keyword", + ["if"] = "keyword", + ["impl"] = "keyword", + ["in"] = "keyword", + ["let"] = "keyword", + ["loop"] = "keyword", + ["match"] = "keyword", + ["mod"] = "keyword", + ["move"] = "keyword", + ["mut"] = "keyword", + ["pub"] = "keyword", + ["ref"] = "keyword", + ["return"] = "keyword", + ["Self"] = "keyword", + ["self"] = "keyword", + ["static"] = "keyword", + ["struct"] = "keyword", + ["super"] = "keyword", + ["trait"] = "keyword", + ["type"] = "keyword", + ["unsafe"] = "keyword", + ["use"] = "keyword", + ["where"] = "keyword", + ["while"] = "keyword", + ["i32"] = "keyword2", + ["i64"] = "keyword2", + ["i128"] = "keyword2", + ["i16"] = "keyword2", + ["i8"] = "keyword2", + ["u8"] = "keyword2", + ["u16"] = "keyword2", + ["u32"] = "keyword2", + ["u64"] = "keyword2", + ["usize"] = "keyword2", + ["isize"] = "keyword2", + ["f32"] = "keyword2", + ["f64"] = "keyword2", + ["f128"] = "keyword2", + ["String"] = "keyword2", + ["char"] = "keyword2", + ["str"] = "keyword2", + ["bool"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + ["None"] = "literal", + ["Some"] = "literal", + ["Option"] = "literal", + ["Result"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_sass.lua b/debian/extra/plugins/language_sass.lua new file mode 100644 index 0000000..f440927 --- /dev/null +++ b/debian/extra/plugins/language_sass.lua @@ -0,0 +1,47 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Sass", + files = { "%.sass$" ,"%.scss$"}, + comment = "//", + patterns = { + { pattern = "/[/%*].-\n", type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "$%w+", type = "keyword" }, + { pattern = "@%w+", type = "literal" }, + { pattern = "[#,]%w+", type = "function" }, + { pattern = "&", type = "keyword2" }, + { pattern = "[:%/%*%-]", type = "operator" }, + { pattern = "[%a][%w-]*%s*%f[:]", type = "keyword2" }, + { pattern = "-?%d+[%d%.]*p[xt]", type = "number" }, + { pattern = "-?%d+[%d%.]*deg", type = "number" }, + { pattern = "-?%d+[%d%.]*[s%%]", type = "number" }, + { pattern = "-?%d+[%d%.]*", type = "number" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["transparent"] = "literal", + ["none"] = "literal", + ["absolute"] = "literal", + ["relative"] = "literal", + ["solid"] = "literal", + ["flex"] = "literal", + ["flex-start"] = "literal", + ["flex-end"] = "literal", + ["row"] = "literal", + ["center"] = "literal", + ["column"] = "literal", + ["pointer"] = "literal", + ["ease"] = "literal", + ["white"] = "function", + ["black"] = "function", + ["gray"] = "function", + ["blue"] = "function", + ["red"] = "function", + ["purple"] = "function", + ["green"] = "function", + ["yellow"] = "function" + } +} diff --git a/debian/extra/plugins/language_scala.lua b/debian/extra/plugins/language_scala.lua new file mode 100644 index 0000000..6c5d7a7 --- /dev/null +++ b/debian/extra/plugins/language_scala.lua @@ -0,0 +1,80 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Scala", + files = { "%.sc$", "%.scala$" }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '[ruU]?"', '"', '\\' }, type = "string" }, + { pattern = { "[ruU]?'", "'", '\\' }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = '[%a_][%w_]*"""*[%a_][%w_]*"""', type = "string" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["abstract"] = "keyword", + ["case"] = "keyword", + ["catch"] = "keyword", + ["class"] = "keyword", + ["finally"] = "keyword", + ["final"] = "keyword", + ["do"] = "keyword", + ["extends"] = "keyword", + ["forSome"] = "keyword", + ["implicit"] = "keyword", + ["lazy"] = "keyword", + ["match"] = "keyword", + ["new"] = "keyword", + ["override"] = "keyword", + ["package"] = "keyword", + ["throw"] = "keyword", + ["trait"] = "keyword", + ["type"] = "keyword", + ["var"] = "keyword", + ["val"] = "keyword", + ["println"] = "keyword", + ["return"] = "keyword", + ["for"] = "keyword", + ["Try"] = "keyword", + ["def"] = "keyword", + ["while"] = "keyword", + ["with"] = "keyword", + ["if"] = "keyword", + ["else"] = "keyword", + ["import"] = "keyword", + ["object"] = "keyword", + ["yield"] = "keyword", + + ["private"] = "keyword2", + ["protected"] = "keyword2", + ["sealed"] = "keyword2", + ["super"] = "keyword2", + ["this"] = "keyword2", + ["Byte"] = "keyword2", + ["Short"] = "keyword2", + ["Int"] = "keyword2", + ["Long"] = "keyword2", + ["Float"] = "keyword2", + ["Double"] = "keyword2", + ["Char"] = "keyword2", + ["String"] = "keyword2", + ["List"] = "keyword2", + ["Array"] = "keyword2", + ["Boolean"] = "keyword2", + + ["Null"] = "literal", + ["Any"] = "literal", + ["AnyRef"] = "literal", + ["Nothing"] = "literal", + ["Unit"] = "literal", + ["true"] = "literal", + ["false"] = "literal", + } +} diff --git a/debian/extra/plugins/language_sh.lua b/debian/extra/plugins/language_sh.lua new file mode 100644 index 0000000..dbc0c82 --- /dev/null +++ b/debian/extra/plugins/language_sh.lua @@ -0,0 +1,103 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Shell script", + files = { + "%.sh$", "%.bash$", + PATHSEP .. "%.bashrc$", PATHSEP .. "%.bash_profile$", PATHSEP .. "%.profile$", + "%.zsh$", "%.fish$", + PATHSEP .. "APKBUILD$", + }, + headers = "^#!.*bin.*sh\n", + comment = "#", + patterns = { + -- $# is a bash special variable and the '#' shouldn't be interpreted + -- as a comment. + { pattern = "%$[%a_@*#][%w_]*", type = "keyword2" }, + -- Comments + { pattern = "#.*", type = "comment" }, + -- Strings + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { '`', '`', '\\' }, type = "string" }, + -- Ignore numbers that start with dots or slashes + { pattern = "%f[%w_%.%/]%d[%d%.]*%f[^%w_%.]", type = "number" }, + -- Operators + { pattern = "[!<>|&%[%]:=*]", type = "operator" }, + -- Match parameters + { pattern = "%f[%S][%+%-][%w%-_:]+", type = "function" }, + { pattern = "%f[%S][%+%-][%w%-_]+%f[=]", type = "function" }, + -- Prevent parameters with assignments from been matched as variables + { + pattern = "%s%-%a[%w_%-]*%s+()%d[%d%.]+", + type = { "function", "number" } + }, + { + pattern = "%s%-%a[%w_%-]*%s+()%a[%a%-_:=]+", + type = { "function", "symbol" } + }, + -- Match variable assignments + { pattern = "[_%a][%w_]+%f[%+=]", type = "keyword2" }, + -- Match variable expansions + { pattern = "%${.-}", type = "keyword2" }, + { pattern = "%$[%d%$%a_@*][%w_]*", type = "keyword2" }, + -- Everything else + { pattern = "[%a_][%w_]*", type = "symbol" }, + -- Functions + { pattern = "[%a_%-][%w_%-]*[%s]*%f[(]", type = "function" }, + }, + symbols = { + ["case"] = "keyword", + ["in"] = "keyword", + ["esac"] = "keyword", + ["if"] = "keyword", + ["then"] = "keyword", + ["elif"] = "keyword", + ["else"] = "keyword", + ["fi"] = "keyword", + ["while"] = "keyword", + ["do"] = "keyword", + ["done"] = "keyword", + ["for"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["function"] = "keyword", + ["local"] = "keyword", + ["echo"] = "keyword", + ["return"] = "keyword", + ["exit"] = "keyword", + ["alias"] = "keyword", + ["test"] = "keyword", + ["cd"] = "keyword", + ["declare"] = "keyword", + ["enable"] = "keyword", + ["eval"] = "keyword", + ["exec"] = "keyword", + ["export"] = "keyword", + ["getopts"] = "keyword", + ["hash"] = "keyword", + ["history"] = "keyword", + ["help"] = "keyword", + ["jobs"] = "keyword", + ["kill"] = "keyword", + ["let"] = "keyword", + ["mapfile"] = "keyword", + ["printf"] = "keyword", + ["read"] = "keyword", + ["readarray"] = "keyword", + ["pwd"] = "keyword", + ["select"] = "keyword", + ["set"] = "keyword", + ["shift"] = "keyword", + ["source"] = "keyword", + ["time"] = "keyword", + ["type"] = "keyword", + ["until"] = "keyword", + ["unalias"] = "keyword", + ["unset"] = "keyword", + ["true"] = "literal", + ["false"] = "literal" + } +} + diff --git a/debian/extra/plugins/language_ssh_config.lua b/debian/extra/plugins/language_ssh_config.lua new file mode 100644 index 0000000..d507ef4 --- /dev/null +++ b/debian/extra/plugins/language_ssh_config.lua @@ -0,0 +1,58 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "SSH config", + files = { PATHSEP .. "sshd?" .. PATHSEP .. "?_?config$" }, + comment = '#', + patterns = { + { pattern = "#.*", type = "comment" }, + { pattern = "%d+", type = "number" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "@", type = "operator" }, + }, + symbols = { + -- ssh config + ["Host"] = "function", + ["ProxyCommand"] = "function", + + ["HostName"] = "keyword", + ["IdentityFile"] = "keyword", + ["IdentitiesOnly"] = "keyword", + ["User"] = "keyword", + ["Port"] = "keyword", + + ["ForwardAgent"] = "keyword", + ["ForwardX11"] = "keyword", + ["ForwardX11Trusted"] = "keyword", + ["HostbasedAuthentication"] = "keyword", + ["GSSAPIAuthentication"] = "keyword", + ["GSSAPIDelegateCredentials"] = "keyword", + ["GSSAPIKeyExchange"] = "keyword", + ["GSSAPITrustDNS"] = "keyword", + ["BatchMode"] = "keyword", + ["CheckHostIP"] = "keyword", + ["AddressFamily"] = "keyword", + ["ConnectTimeout"] = "keyword", + ["StrictHostKeyChecking"] = "keyword", + ["Ciphers"] = "keyword", + ["MACs"] = "keyword", + ["EscapeChar"] = "keyword", + ["Tunnel"] = "keyword", + ["TunnelDevice"] = "keyword", + ["PermitLocalCommand"] = "keyword", + ["VisualHostKey"] = "keyword", + ["RekeyLimit"] = "keyword", + ["SendEnv"] = "keyword", + ["HashKnownHosts"] = "keyword", + + -- sshd config + ["Subsystem"] = "keyword2", + + + ["yes"] = "literal", + ["no"] = "literal", + ["any"] = "literal", + ["ask"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_st.lua b/debian/extra/plugins/language_st.lua new file mode 100644 index 0000000..f679193 --- /dev/null +++ b/debian/extra/plugins/language_st.lua @@ -0,0 +1,125 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +-- Language Syntax References +-- https://pdhonline.com/courses/e334/e334content.pdf + +syntax.add { + name = "PLC Structured Text IEC 61131-3", + files = { "%.stx?$", "%.iecst$" }, + comment = "//", + block_comment = { "%(%*", "%*%)" }, + patterns = { + { pattern = "//.*", type = "comment" }, -- Single-line comment + { pattern = { "%(%*", "%*%)" }, type = "comment" }, -- Multi-line comment + { pattern = { '"', '"', '\\' }, type = "string" }, -- String, quotation marks + { pattern = { "'", "'", '\\' }, type = "string" }, -- String, apices + { pattern = "%w+#[0-9]+m?s?", type = "number" }, -- Time/Date formats + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- Function + { pattern = "[%a_][%w_]*", type = "symbol" }, -- Symbols + { pattern = ":%s*%w[%w_]*", type = "keyword2" }, -- Variable/Method Type + { regex = [[[-+]?\d+\.{2,4}[-+]?\d+]], type = "number" }, -- Number Range + { pattern = "[%+%-=/%*%^%%<>!~|&:]", type = "operator" }, -- Operators + { pattern = "-?0x%x+", type = "number" }, -- Number + { pattern = "-?%d+[%deE]*f?", type = "number" }, -- Number + { pattern = "-?%.?%d+f?", type = "number" }, -- Number + }, + symbols = { + ["PROGRAM"] = "keyword", + ["PROGRAM_INIT"] = "keyword", + ["PROGRAM_CYCLIC"] = "keyword", + + ["PROGRAM_CLOSE"] = "keyword", + ["END_PROGRAM"] = "keyword", + ["FUNCTION_BLOCK"] = "keyword", + ["END_FUNCTION_BLOCK"] = "keyword", + ["FUNCTION"] = "keyword", + ["END_FUNCTION"] = "keyword", + ["METHOD"] = "keyword", + ["END_METHOD"] = "keyword", + ["IMPLEMENTATION"] = "keyword", + ["END_IMPLEMENTATION"] = "keyword", + ["INTERFACE"] = "keyword", + ["END_INTERFACE"] = "keyword", + + ["IF"] = "keyword", + ["THEN"] = "keyword", + ["ELSE"] = "keyword", + ["ELSIF"] = "keyword", + ["END_IF"] = "keyword", + ["CASE"] = "keyword", + ["END_CASE"] = "keyword", + ["OF"] = "keyword", + ["FOR"] = "keyword", + ["TO"] = "keyword", + ["BY"] = "keyword", + ["DO"] = "keyword", + ["END_FOR"] = "keyword", + ["WHILE"] = "keyword", + ["END_WHILE"] = "keyword", + ["REPEAT"] = "keyword", + ["END_REPEAT"] = "keyword", + + ["MOD"] = "operator", + ["UNTIL"] = "operator", + ["EXIT"] = "keyword", + ["RETURN"] = "keyword", + + ["AND"] = "keyword", + ["NOT"] = "keyword", + ["OR"] = "keyword", + ["XOR"] = "keyword", + + ["NAMESPACE"] = "keyword", + ["END_NAMESPACE"] = "keyword", + + ["VAR"] = "keyword", + ["VAR_GLOBAL"] = "keyword", + ["VAR_INPUT"] = "keyword", + ["VAR_OUTPUT"] = "keyword", + ["VAR_IN_OUT"] = "keyword", + ["VAR_ACCESS"] = "keyword", + ["VAR_EXTERNAL"] = "keyword", + ["VAR_TEMP"] = "keyword", + ["AT"] = "keyword", + ["RETAIN"] = "keyword", + ["END_VAR"] = "keyword", + ["CONST"] = "keyword", + ["END_CONST"] = "keyword", + + ["TYPE"] = "keyword", + ["END_TYPE"] = "keyword", + ["STRUCT"] = "keyword", + ["END_STRUCT"] = "keyword", + + ["ORGANIZATION_BLOCK"] = "keyword", + ["END_ORGANIZATION_BLOCK"] = "keyword", + + ["TRUE"] = "literal", + ["FALSE"] = "literal", + ["true"] = "literal", + ["false"] = "literal", + + ["SINT"] = "keyword2", + ["INT"] = "keyword2", + ["DINT"] = "keyword2", + ["LINT"] = "keyword2", + ["USINT"] = "keyword2", + ["UINT"] = "keyword2", + ["UDINT"] = "keyword2", + ["ULINT"] = "keyword2", + ["LDINT"] = "keyword2", + ["REAL"] = "keyword2", + ["LREAL"] = "keyword2", + ["TIME"] = "keyword2", + ["DATE"] = "keyword2", + ["TIME_OF_DAY"] = "keyword2", + ["DATE_AND_TIME"] = "keyword2", + ["STRING"] = "keyword2", + ["BOOL"] = "keyword2", + ["BYTE"] = "keyword2", + ["WORD"] = "keyword2", + ["DWORD"] = "keyword2", + ["LWORD"] = "keyword2", + } +} diff --git a/debian/extra/plugins/language_starlark.lua b/debian/extra/plugins/language_starlark.lua new file mode 100644 index 0000000..8ab4899 --- /dev/null +++ b/debian/extra/plugins/language_starlark.lua @@ -0,0 +1,101 @@ +--- Author: Rohan Vashisht: https://github.com/rohanvashisht1234/ +-- mod-version:3 +------------ IMPORT LIB ------------ +local syntax_highlight = require("core.syntax") +------------------------------------ + +------------- DATABASE ------------- + +---- SYMBOLS ---- +local SYMBOLS = {} + +local KEYWORDS = { + "break", + "continue", + "elif", + "else", + "for", + "if", + "pass", + "return", + "True", + "False" +} + +local KEYWORDS2 = { + "as", + "assert", + "class", + "del", + "except", + "finally", + "from", + "global", + "import", + "in", + "is", + "lambda", + "nonlocal", + "raise", + "try", + "while", + "with", + "yield" +} + +local LITERALS = { + "all", + "any", + "bool", + "dict", + "dir", + "enumerate", + "getattr", + "hasattr", + "hash", + "int", + "len", + "list", + "load", + "max", + "min", + "repr", + "reversed", + "sorted", + "str", + "tuple", + "type", + "zip" +} +----------------- + +---- PATTERNS ---- +local PATTERNS = { + { pattern = { '"', '"', '\\' }, type = "string" }, -- tested ok + { pattern = "#.*", type = "comment" }, -- tested ok + { pattern = "[!%-/*?:=><]", type = "operator" }, -- tested ok + { pattern = "-?%d+[%d%.eE_]*", type = "number" }, -- tested ok + { pattern = '[%a_][%w_]*%f[(]', type = 'function' }, -- tested ok + { pattern = "[%a_][%w_]*", type = "normal" } -- tested ok +} +------------------ +------------------------------------ + +--------------- MAIN --------------- +for _, keyword in ipairs(KEYWORDS) do + SYMBOLS[keyword] = "keyword" +end +for _, keyword2 in ipairs(KEYWORDS2) do + SYMBOLS[keyword2] = "keyword2" +end +for _, literal in ipairs(LITERALS) do + SYMBOLS[literal] = "literal" +end +syntax_highlight.add { + name = "Starlark", + files = {"%.bazel$","%.bzl$"}, + comment = "#", + patterns = PATTERNS, + symbols = SYMBOLS, +} +------------------------------------ diff --git a/debian/extra/plugins/language_swift.lua b/debian/extra/plugins/language_swift.lua new file mode 100644 index 0000000..b428899 --- /dev/null +++ b/debian/extra/plugins/language_swift.lua @@ -0,0 +1,149 @@ +-- Author: Rohan Vashisht: https://github.com/rohanvashisht1234/ + + +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Swift", + files = { "%.swift$" }, + comment = "//", + patterns = { + { pattern = { '"', '"', '\\' }, type = "string" }, -- tested ok + { pattern = { '"""', '"""', '\\' }, type = "string" }, -- tested ok + { pattern = { '#"', '"#', '\\' }, type = "string" }, -- tested ok + { pattern = { '#"""', '"""#', '\\' }, type = "string" }, -- tested ok + { pattern = "//.*", type = "comment" }, -- tested ok + { pattern = { "/%*", "%*/" }, type = "comment" }, -- tested ok + { pattern = "[!%-/*?:=><+]", type = "operator" }, -- tested ok + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- tested ok + { pattern = "let()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "var()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "import()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "struct()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "class()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + { pattern = "enum()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok + + { pattern = "-?%d+[%d%.eE_]*", type = "number" }, -- tested ok + { pattern = "-?%.?%d+", type = "number" }, -- tested ok + { pattern = "[%a_][%w_]*", type = "normal" }, -- tested ok + }, + symbols = { + ["import"] = "keyword", -- tested ok + ["inout"] = "keyword", -- tested ok + ["internal"] = "keyword", -- tested ok + ["let"] = "keyword", -- tested ok + ["Let"] = "keyword", -- tested ok + ["open"] = "keyword", -- tested ok + ["operator"] = "keyword", -- tested ok + ["private"] = "keyword", -- tested ok + ["precedencegroup"] = "keyword", -- tested ok + ["protocol"] = "keyword", -- tested ok + ["public"] = "keyword", -- tested ok + ["rethrows"] = "keyword", -- tested ok + ["static"] = "keyword", -- tested ok + ["struct"] = "keyword", -- tested ok + ["subscript"] = "keyword", -- tested ok + ["typealias"] = "keyword", -- tested ok + ["var"] = "keyword", -- tested ok + ["break"] = "keyword", -- tested ok + ["while"] = "keyword", -- tested ok + ["nil"] = "keyword", -- tested ok + ["associativity"] = "keyword", -- tested ok + ["convenience"] = "keyword", -- tested ok + ["didSet"] = "keyword", -- tested ok + ["dynamic"] = "keyword", -- tested ok + ["final"] = "keyword", -- tested ok + ["get"] = "keyword", -- tested ok + ["indirect"] = "keyword", -- tested ok + ["infix"] = "keyword", -- tested ok + ["left"] = "keyword", -- tested ok + ["mutating"] = "keyword", -- tested ok + ["none"] = "keyword", -- tested ok + ["nonmutating"] = "keyword", -- tested ok + ["optional"] = "keyword", -- tested ok + ["override"] = "keyword", -- tested ok + ["postfix"] = "keyword", -- tested ok + ["Protocol"] = "keyword", -- tested ok + ["required"] = "keyword", -- tested ok + ["right"] = "keyword", -- tested ok + ["set"] = "keyword", -- tested ok + ["some"] = "keyword", -- tested ok + ["Type"] = "keyword", -- tested ok + ["unowned"] = "keyword", -- tested ok + ["weak"] = "keyword", -- tested ok + ["lazy"] = "keyword", -- tested ok + ["prefix"] = "keyword", -- tested ok + ["willSet"] = "keyword", -- tested ok + ["try"] = "keyword", -- tested ok + ["true"] = "keyword", -- tested ok + ["throws"] = "keyword", -- tested ok + ["super"] = "keyword", -- tested ok + ["Self"] = "keyword", -- tested ok + ["self"] = "keyword", -- tested ok + ["is"] = "keyword", -- tested ok + ["false"] = "keyword", -- tested ok + ["as"] = "keyword", -- tested ok + ["Any"] = "keyword", -- tested ok + ["where"] = "keyword", -- tested ok + ["switch"] = "keyword", -- tested ok + ["throw"] = "keyword", -- tested ok + ["catch"] = "keyword", -- tested ok + ["return"] = "keyword", -- tested ok + ["repeat"] = "keyword", -- tested ok + ["in"] = "keyword", -- tested ok + ["if"] = "keyword", -- tested ok + ["gaurd"] = "keyword", -- tested ok + ["for"] = "keyword", -- tested ok + ["fallthrough"] = "keyword", -- tested ok + ["else"] = "keyword", -- tested ok + ["do"] = "keyword", -- tested ok + ["defer"] = "keyword", -- tested ok + ["default"] = "keyword", -- tested ok + ["continue"] = "keyword", -- tested ok + ["case"] = "keyword", -- tested ok + ["init"] = "keyword", -- tested ok + ["func"] = "keyword", -- tested ok + ["fileprivate"] = "keyword", -- tested ok + ["extension"] = "keyword", -- tested ok + ["associatedtype"] = "keyword", -- tested ok + ["enum"] = "keyword", -- tested ok + ["Init"] = "keyword", -- tested ok + ["Enum"] = "keyword", -- tested ok + ["deinit"] = "keyword", -- tested ok + ["class"] = "keyword", -- tested ok + ["Class"] = "keyword", -- tested ok + ["precedence"] = "keyword", -- tested ok + + ["#available"] = "keyword2", -- tested ok + ["#colorLiteral"] = "keyword2", -- tested ok + ["#column"] = "keyword2", -- tested ok + ["#dsohandle"] = "keyword2", -- tested ok + ["#elseif"] = "keyword2", -- tested ok + ["#else"] = "keyword2", -- tested ok + ["#endif"] = "keyword2", -- tested ok + ["#error"] = "keyword2", -- tested ok + ["#keyPath"] = "keyword2", -- tested ok + ["#line"] = "keyword2", -- tested ok + ["#selector"] = "keyword2", -- tested ok + ["#sourceLocation"] = "keyword2", -- tested ok + ["#warning"] = "keyword2", -- tested ok + ["_COLUMN_"] = "keyword2", -- tested ok + ["_FILE_"] = "keyword2", -- tested ok + ["_FUNCTION_"] = "keyword2", -- tested ok + ["_LINE_"] = "keyword2", -- tested ok + ["String"] = "keyword2", -- tested ok + ["Int"] = "keyword2", -- tested ok + ["Int8"] = "keyword2", -- tested ok + ["Int16"] = "keyword2", -- tested ok + ["Int32"] = "keyword2", -- tested ok + ["Int64"] = "keyword2", -- tested ok + ["UInt8"] = "keyword2", -- tested ok + ["UInt16"] = "keyword2", -- tested ok + ["UInt32"] = "keyword2", -- tested ok + ["UInt64"] = "keyword2", -- tested ok + ["Float"] = "keyword2", -- tested ok + ["Bool"] = "keyword2", -- tested ok + ["at"] = "keyword2", -- tested ok + } +} diff --git a/debian/extra/plugins/language_tal.lua b/debian/extra/plugins/language_tal.lua new file mode 100644 index 0000000..aef83cd --- /dev/null +++ b/debian/extra/plugins/language_tal.lua @@ -0,0 +1,70 @@ +--mod-version:3 +local syntax = require 'core.syntax' + +local label, sublabel = "function", "keyword2" + +syntax.add { + name = "Uxntal", + files = { "%.tal$" }, + block_comment = { '(', ')' }, + patterns = { + { pattern = {'%(', '%)'}, type = "comment" }, + { pattern = "@%S*%s+%f[[]", type = label }, + { pattern = "@%S+", type = "string" }, + { pattern = "%u+()[2kr]*", type = { "symbol", "keyword" } }, + { pattern = "%%%S+", type = "keyword" }, + { pattern = "&%S+", type = sublabel }, + { pattern = "\"%S+", type = "string" }, + { pattern = "%.%S+()/%S*", type = { label, sublabel } }, + { pattern = "%.%S+", type = label }, + { pattern = "|%x+", type = "string" }, + { pattern = "[.,;_=-]%S+", type = sublabel }, + { pattern = "%$%d+", type = "number" }, + { pattern = "#?%x%x%x%x%f[%X]", type = "number" }, + { pattern = "#?%x%x%f[%X]", type = "number" }, + { pattern = "[!?]()[^%[%]{}%s]+", type = { "operator", "function" } }, + { pattern = "[^%[%]{}%s]+", type = "function" }, + }, + symbols = { + -- no mode keywords + ["JCI"] = "keyword", + ["JMI"] = "keyword", + ["JSI"] = "keyword", + ["BRK"] = "keyword", + + -- lit only has 4 modes + ["LIT"] = "keyword", + + -- the rest + ["EQU"] = "keyword", + ["LDZ"] = "keyword", + ["ADD"] = "keyword", + ["INC"] = "keyword", + ["NEQ"] = "keyword", + ["STZ"] = "keyword", + ["SUB"] = "keyword", + ["POP"] = "keyword", + ["GTH"] = "keyword", + ["LDR"] = "keyword", + ["MUL"] = "keyword", + ["NIP"] = "keyword", + ["LTH"] = "keyword", + ["STR"] = "keyword", + ["DIV"] = "keyword", + ["SWP"] = "keyword", + ["JMP"] = "keyword", + ["LDA"] = "keyword", + ["AND"] = "keyword", + ["ROT"] = "keyword", + ["JCN"] = "keyword", + ["STA"] = "keyword", + ["ORA"] = "keyword", + ["DUP"] = "keyword", + ["JSR"] = "keyword", + ["DEI"] = "keyword", + ["EOR"] = "keyword", + ["OVR"] = "keyword", + ["STH"] = "keyword", + ["DEO"] = "keyword", + ["SFT"] = "keyword", + }} diff --git a/debian/extra/plugins/language_tau.lua b/debian/extra/plugins/language_tau.lua new file mode 100644 index 0000000..765ee36 --- /dev/null +++ b/debian/extra/plugins/language_tau.lua @@ -0,0 +1,95 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Tau", + files = { "%.tau$" }, + comment = "#", + patterns = { + { pattern = { '{', '}' }, type = "operator", syntax = ".tau" }, + -- funtion declaration + { + pattern = { '%.?()[%a_][%w_]*()%s*=%s*()fn()%(', '%)%s*' }, + type = { "operator", "function", "operator", "keyword", "normal" }, + syntax = { + patterns = { + { pattern = '[%a_][%w_]*', type = "literal" }, + }, + symbols = { + [','] = "normal", + }, + }, + }, + -- strings + { pattern = { "`", "`" }, type = "string" }, + { pattern = { '\\"', '\\"' }, type = "string" }, + { + pattern = { '"', '"', '\\' }, + type = "string", + syntax = { + -- TODO: formatted strings has still some issues with inner {} blocks like if { .. } else { ... } and escaped \"strings\" + patterns = { + { pattern = { '{', '}' }, type = "operator", syntax = ".tau" }, + { pattern = '[^%s"]+', type = "string" }, + }, + symbols = {}, + }, + }, + + -- numbers and values + { pattern = "0b[01]{0,64}", type = "number" }, + { pattern = "0o[0-7]{0,24}", type = "number" }, + { pattern = "0x[%da-fA-F]{0,16}", type = "number" }, + { pattern = "-?%d{0,20}", type = "number" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + + -- others + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "%.?()[%a_][%w_]*%f[(]", type = { "operator", "function" } }, + { pattern = "%.()[%a_][%w_]*", type = { "operator", "literal" } }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + -- actual keywords + ["if"] = "keyword", + ["else"] = "keyword", + ["for"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["tau"] = "keyword", + ["fn"] = "keyword", + ["return"] = "keyword", + + -- literal values + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + + -- builtin functions + ["new"] = "keyword2", + ["len"] = "keyword2", + ["println"] = "keyword2", + ["print"] = "keyword2", + ["input"] = "keyword2", + ["string"] = "keyword2", + ["error"] = "keyword2", + ["type"] = "keyword2", + ["int"] = "keyword2", + ["float"] = "keyword2", + ["exit"] = "keyword2", + ["append"] = "keyword2", + ["newfailed"] = "keyword2", + ["plugin"] = "keyword2", + ["pipesend"] = "keyword2", + ["recv"] = "keyword2", + ["close"] = "keyword2", + ["hex"] = "keyword2", + ["oct"] = "keyword2", + ["bin"] = "keyword2", + ["slice"] = "keyword2", + ["keys"] = "keyword2", + ["delete"] = "keyword2" + }, +} + diff --git a/debian/extra/plugins/language_tcl.lua b/debian/extra/plugins/language_tcl.lua new file mode 100644 index 0000000..7a6e13f --- /dev/null +++ b/debian/extra/plugins/language_tcl.lua @@ -0,0 +1,69 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Tcl", + files = { "%.tcl$" }, + comment = "#", + patterns = { + { pattern = "#.-\n", type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = "0x%x+", type = "number" }, + { pattern = "%d+[%d%.eE]*f?", type = "number" }, + { pattern = "%.?%d+f?", type = "number" }, + { pattern = "%$[%a_][%w_]*", type = "literal" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "::[%a_][%w_]*", type = "function" }, + { pattern = "[%a_][%w_]*%f[:]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["set"] = "keyword", + ["unset"] = "keyword", + ["rename"] = "keyword", + ["upvar"] = "keyword", + ["incr"] = "keyword", + ["source"] = "keyword", + ["expr"] = "keyword", + ["gets"] = "keyword", + ["puts"] = "keyword", + ["package"] = "keyword", + ["list"] = "keyword", + ["dict"] = "keyword", + ["split"] = "join", + ["concat"] = "join", + ["lappend"] = "keyword", + ["lset"] = "keyword", + ["lassign"] = "keyword", + ["lindex"] = "keyword", + ["llength"] = "keyword", + ["lsearch"] = "keyword", + ["lrange"] = "keyword", + ["linsert"] = "keyword", + ["lreplace"] = "keyword", + ["lrepeat"] = "keyword", + ["lsort"] = "keyword", + ["lreverse"] = "keyword", + ["array"] = "keyword", + ["concat"] = "keyword", + ["regexp"] = "keyword", + ["for"] = "keyword", + ["foreach"] = "keyword", + ["while"] = "keyword", + ["case"] = "keyword", + ["proc"] = "keyword", + ["if"] = "keyword", + ["else"] = "keyword", + ["elseif"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["return"] = "keyword", + ["eval"] = "keyword", + ["try"] = "keyword2", + ["on"] = "keyword2", + ["finally"] = "keyword2", + ["throw"] = "keyword2", + ["error"] = "keyword2", + }, +} + diff --git a/debian/extra/plugins/language_teal.lua b/debian/extra/plugins/language_teal.lua new file mode 100644 index 0000000..0b0e35d --- /dev/null +++ b/debian/extra/plugins/language_teal.lua @@ -0,0 +1,57 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Teal", + files = {"%.tl$","%.d.tl$"}, + comment = "--", + patterns = { + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "%[%[", "%]%]" }, type = "string" }, + { pattern = { "%-%-%[%[", "%]%]"}, type = "comment" }, + { pattern = "%-%-.-\n", type = "comment" }, + { pattern = "-?0x%x+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "<%a+>", type = "keyword2" }, + { pattern = "%.%.%.?", type = "operator" }, + { pattern = "[<>~=]=", type = "operator" }, + { pattern = "[%+%-=/%*%^%%#<>]", type = "operator" }, + { pattern = "[%a_][%w_]*%s*%f[(\"{]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "::[%a_][%w_]*::", type = "function" }, + }, + symbols = { + ["if"] = "keyword", + ["then"] = "keyword", + ["else"] = "keyword", + ["elseif"] = "keyword", + ["end"] = "keyword", + ["do"] = "keyword", + ["function"] = "keyword", + ["repeat"] = "keyword", + ["until"] = "keyword", + ["while"] = "keyword", + ["for"] = "keyword", + ["break"] = "keyword", + ["return"] = "keyword", + ["local"] = "keyword", + ["global"] = "keyword", + ["in"] = "keyword", + ["not"] = "keyword", + ["and"] = "keyword", + ["or"] = "keyword", + ["goto"] = "keyword", + ["enum"] = "keyword", + ["record"] = "keyword", + ["any"] = "keyword2", + ["boolean"] = "keyword2", + ["number"] = "keyword2", + ["string"] = "keyword2", + ["thread"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + ["nil"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_tex.lua b/debian/extra/plugins/language_tex.lua new file mode 100644 index 0000000..f8e69e2 --- /dev/null +++ b/debian/extra/plugins/language_tex.lua @@ -0,0 +1,27 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "TeX", + files = { "%.tex$", "%.dtx$", "%.sty$", "%.ins$", "%.cls$" }, + comment = "%%", + patterns = { + { pattern = "%%.-\n", type = "comment" }, + { pattern = "\\documentclass().-{()%a%w+()}", type = {"keyword", "symbol", "function", "symbol"} }, + { pattern = "\\usepackage", type = "keyword" }, + { pattern = "\\chapter", type = "keyword" }, + { pattern = "\\section", type = "keyword" }, + { pattern = "\\subsection", type = "keyword" }, + { pattern = "\\paragraph", type = "keyword" }, + { pattern = "\\subparagraph", type = "keyword" }, + { pattern = "\\begin(){()%a%w+()}", type = {"keyword2", "symbol", "function", "symbol"} }, + { pattern = "\\end(){()%a%w+()}", type = {"keyword2", "symbol", "function", "symbol"} }, + { pattern = "\\%a%w+()%*", type = {"keyword2", "operator"} }, + { pattern = "\\%a%w+", type = "keyword2" }, + { pattern = "&", type = "operator" }, + { pattern = "\\\\", type = "operator" }, + { pattern = "%$", type = "operator" }, + { pattern = "\\[%[%]()]", type = "operator" }, + }, + symbols = {} +} diff --git a/debian/extra/plugins/language_toml.lua b/debian/extra/plugins/language_toml.lua new file mode 100644 index 0000000..eb3a2d7 --- /dev/null +++ b/debian/extra/plugins/language_toml.lua @@ -0,0 +1,40 @@ +-- mod-version:3 + +local syntax = require "core.syntax" + +syntax.add { + name = "TOML", + files = { "%.toml$" }, + comment = '#', + + patterns = { + { pattern = "#.*", type = "comment" }, + + { pattern = { '"""', '"""', '\\' }, type = "string" }, + { pattern = { "'''", "'''" }, type = "string" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'" }, type = "string" }, + + { pattern = "[%w_%.%-]+%s*%f[=]", type = "function" }, + + { pattern = {"^%s*%[", "%]"}, type = "keyword" }, + + { pattern = "0x[%x_]+", type = "number" }, + { pattern = "0o[0-7_]+", type = "number" }, + { pattern = "0b[01_]+", type = "number" }, + { pattern = "%d[%d_]*%.?[%d_]*[eE][%-+]?[%d_]+", type = "number" }, + { pattern = "%d[%d_]*%.?[$d_]*", type = "number" }, + { pattern = "%f[-+%w_][-+]%f[%w%.]", type = "number" }, + + { pattern = "[%+%-:TZ]", type = "operator" }, + { pattern = "%a+", type = "symbol" }, + }, + + symbols = { + ["true"] = "literal", + ["false"] = "literal", + + ["nan"] = "number", + ["inf"] = "number" + }, +} diff --git a/debian/extra/plugins/language_ts.lua b/debian/extra/plugins/language_ts.lua new file mode 100644 index 0000000..f28261d --- /dev/null +++ b/debian/extra/plugins/language_ts.lua @@ -0,0 +1,74 @@ +-- mod-version:3 +-- copied from language_js, but added regex highlighting back +local syntax = require "core.syntax" + +syntax.add { + name = "TypeScript", + files = { "%.ts$" }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '/%g', '/', '\\' }, type = "string" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "`", "`", '\\' }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "interface%s()[%a_][%w_]*", type = {"keyword", "keyword2"} }, + { pattern = "type%s()[%a_][%w_]*", type = {"keyword", "keyword2"} }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["async"] = "keyword", + ["await"] = "keyword", + ["break"] = "keyword", + ["case"] = "keyword", + ["catch"] = "keyword", + ["class"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["debugger"] = "keyword", + ["default"] = "keyword", + ["delete"] = "keyword", + ["do"] = "keyword", + ["else"] = "keyword", + ["export"] = "keyword", + ["extends"] = "keyword", + ["finally"] = "keyword", + ["for"] = "keyword", + ["function"] = "keyword", + ["get"] = "keyword", + ["if"] = "keyword", + ["import"] = "keyword", + ["implements"] = "keyword", + ["in"] = "keyword", + ["instanceof"] = "keyword", + ["let"] = "keyword", + ["new"] = "keyword", + ["return"] = "keyword", + ["set"] = "keyword", + ["static"] = "keyword", + ["super"] = "keyword", + ["switch"] = "keyword", + ["throw"] = "keyword", + ["try"] = "keyword", + ["typeof"] = "keyword", + ["var"] = "keyword", + ["void"] = "keyword", + ["while"] = "keyword", + ["with"] = "keyword", + ["yield"] = "keyword", + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + ["undefined"] = "literal", + ["arguments"] = "keyword2", + ["Infinity"] = "keyword2", + ["NaN"] = "keyword2", + ["this"] = "keyword2", + }, +} diff --git a/debian/extra/plugins/language_tsx.lua b/debian/extra/plugins/language_tsx.lua new file mode 100644 index 0000000..f6073ab --- /dev/null +++ b/debian/extra/plugins/language_tsx.lua @@ -0,0 +1,75 @@ +-- mod-version:3 +-- Almost identical to JS, with the exception that / shouldn't denote a regex. +-- Current JS syntax highlighter will highlight half the document due to closing tags. +local syntax = require "core.syntax" + +syntax.add { + name = "TypeScript with JSX", + files = { "%.tsx$", "%.astro$" }, + comment = "//", + block_comment = { "/*", "*/" }, + patterns = { + { pattern = "//.*", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "`", "`", '\\' }, type = "string" }, + { pattern = "0x[%da-fA-F]+", type = "number" }, + { pattern = "-?%d+[%d%.eE]*", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "interface%s()[%a_][%w_]*", type = {"keyword", "keyword2"} }, + { pattern = "type%s()[%a_][%w_]*", type = {"keyword", "keyword2"} }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["async"] = "keyword", + ["await"] = "keyword", + ["break"] = "keyword", + ["case"] = "keyword", + ["catch"] = "keyword", + ["class"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["debugger"] = "keyword", + ["default"] = "keyword", + ["delete"] = "keyword", + ["do"] = "keyword", + ["else"] = "keyword", + ["export"] = "keyword", + ["extends"] = "keyword", + ["finally"] = "keyword", + ["for"] = "keyword", + ["function"] = "keyword", + ["get"] = "keyword", + ["if"] = "keyword", + ["import"] = "keyword", + ["implements"] = "keyword", + ["in"] = "keyword", + ["instanceof"] = "keyword", + ["let"] = "keyword", + ["new"] = "keyword", + ["return"] = "keyword", + ["set"] = "keyword", + ["static"] = "keyword", + ["super"] = "keyword", + ["switch"] = "keyword", + ["throw"] = "keyword", + ["try"] = "keyword", + ["typeof"] = "keyword", + ["var"] = "keyword", + ["void"] = "keyword", + ["while"] = "keyword", + ["with"] = "keyword", + ["yield"] = "keyword", + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + ["undefined"] = "literal", + ["arguments"] = "keyword2", + ["Infinity"] = "keyword2", + ["NaN"] = "keyword2", + ["this"] = "keyword2", + }, +} diff --git a/debian/extra/plugins/language_typst.lua b/debian/extra/plugins/language_typst.lua new file mode 100644 index 0000000..77b9701 --- /dev/null +++ b/debian/extra/plugins/language_typst.lua @@ -0,0 +1,231 @@ +-- mod-version:3 +local syntax = require "core.syntax" + + +local typst_math = { + + patterns = { + + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = "//.*", type = "comment" }, + + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = "#%a+", type = "literal" }, + { pattern = "%a+%f[(]", type = "function" }, + { pattern = "%a%a+", type = "function" }, + + + { pattern = "0x[%dabcdef]+", type = "number" }, + { pattern = "0b[01]+", type = "number" }, + { pattern = "0o[01234567]+", type = "number" }, + { pattern = "%d+[.e]%d+", type = "number" }, + { pattern = "%d", type = "number" }, + + { pattern = "&", type = "literal" }, + { pattern = "!=", type = "operator" }, + { pattern = "[%+%-=/%*%^%%<>~|_^\\]", type = "operator" }, + { pattern = "%a%a+", type = "symbol" }, + + }, + + symbols = { + ["alpha"] = "keyword2", + ["beta"] = "keyword2", + ["gamma"] = "keyword2", + ["delta"] = "keyword2", + ["epsilon"] = "keyword2", + ["zeta"] = "keyword2", + ["eta"] = "keyword2", + ["theta"] = "keyword2", + ["iota"] = "keyword2", + ["kappa"] = "keyword2", + ["lambda"] = "keyword2", + ["mu"] = "keyword2", + ["nu"] = "keyword2", + ["xi"] = "keyword2", + ["omicron"] = "keyword2", + ["pi"] = "keyword2", + ["rho"] = "keyword2", + ["sigma"] = "keyword2", + ["tau"] = "keyword2", + ["upsilon"] = "keyword2", + ["phi"] = "keyword2", + ["chi"] = "keyword2", + ["psi"] = "keyword2", + ["omega"] = "keyword2", + + ["Alpha"] = "keyword2", + ["Beta"] = "keyword2", + ["Gamma"] = "keyword2", + ["Delta"] = "keyword2", + ["Epsilon"] = "keyword2", + ["Zeta"] = "keyword2", + ["Eta"] = "keyword2", + ["Theta"] = "keyword2", + ["Iota"] = "keyword2", + ["Kappa"] = "keyword2", + ["Lambda"] = "keyword2", + ["Mu"] = "keyword2", + ["Nu"] = "keyword2", + ["Xi"] = "keyword2", + ["Omicron"] = "keyword2", + ["Pi"] = "keyword2", + ["Rho"] = "keyword2", + ["Sigma"] = "keyword2", + ["Tau"] = "keyword2", + ["Upsilon"] = "keyword2", + ["Phi"] = "keyword2", + ["Chi"] = "keyword2", + ["Psi"] = "keyword2", + ["Omega"] = "keyword2", + } +} + +-- there was a bug where the string highlighting did not work properly +-- (probably becuase the tokenizer prioritizes subsyntaxes over clasic start-end patterns) +-- so in order to fix this issue, I had to create this extra sub-syntax. +local typst_string = { + + patterns = { + { pattern = "\\.", type = "string" }, + { pattern = '[^"\\]+', type = "string" } + }, + + symbols = {} +} + + +local typst_script = { + + patterns = { + + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = "//.*", type = "comment" }, + + { pattern = { '"', '"', '\\' }, type = "string", syntax = typst_string }, + { pattern = {"%[", "%]"}, type = "normal", syntax = ".typ" }, + { pattern = "[%a_][%w_%-]*%f[(]", type = "function" }, + { pattern = "[%+%-=/%*%^%%<>~|&_^\\]", type = "operator" }, + { pattern = "%f[^#][%a_]+", type = "literal" }, + { pattern = "#", type = "literal" }, + + { pattern = "0x[%dabcdef]+()%a*", type = {"number", "keyword2"} }, + { pattern = "0b[01]+()%a*", type = {"number", "keyword2"} }, + { pattern = "0o[01234567]+()%a*", type = {"number", "keyword2"} }, + { pattern = "%d+[.e]%d+()%a*", type = {"number", "keyword2"} }, + { pattern = "%d+()%a*", type = {"number", "keyword2"} }, + + { pattern = "%a%a+", type = "symbol" }, + + }, + + + symbols = { + ["set"] = "keyword", + ["let"] = "keyword", + ["show"] = "keyword", + ["include"] = "keyword", + ["import"] = "keyword", + ["context"] = "keyword", + ["if"] = "keyword", + ["else"] = "keyword", + ["for"] = "keyword", + ["in"] = "keyword", + ["while"] = "keyword", + ["break"] = "keyword", + ["continue"] = "keyword", + ["return"] = "keyword", + ["as"] = "keyword", + ["or"] = "keyword", + ["and"] = "keyword", + ["not"] = "keyword", + + ["true"] = "literal", + ["false"] = "literal", + } +} + +table.insert(typst_script.patterns, 1, { pattern = { "%(", "%)" }, syntax = typst_script }) +table.insert(typst_script.patterns, 1, { pattern = { "{", "}" }, syntax = typst_script }) + + + +local typst_syntax = { + name = "Typst", + files = { "%.typ$" }, + comment = "//", + block_comment = { "/*", "*/" }, + + patterns = { + { pattern = { "%[", "%]" }, syntax = ".typ" }, + { + pattern = { "#()import", "\n" }, + type = { "literal", "keyword" }, + syntax = typst_script + }, + { + pattern = { "#()include", "\n" }, + type = { "literal", "keyword" }, + syntax = typst_script + }, + { + pattern = { "#()set", "\n" }, + type = { "literal", "keyword" }, + syntax = typst_script + }, + { + pattern = { "#()let", "\n" }, + type = { "literal", "keyword" }, + syntax = typst_script + }, + { + pattern = { "#()show", "\n" }, + type = { "literal", "keyword" }, + syntax = typst_script + }, + { + pattern = { "#()context", "\n" }, + type = { "literal", "keyword" }, + syntax = typst_script + }, + + { pattern = { "%f[#]", "%f[%s']"}, type = "literal", syntax = typst_script }, + { pattern = { "%$", "%$", "\\" }, type = "literal", syntax = typst_math }, + + { pattern = { "```js" , "```", "\\" }, type = "string", syntax = ".js" }, + { pattern = { "```py", "```", "\\" }, type = "string", syntax = ".py" }, + { pattern = { "```rust", "```", "\\" }, type = "string", syntax = ".rs" }, + { pattern = { "```c", "```", "\\" }, type = "string", syntax = ".c" }, + -- Possibility to add more syntax later + { pattern = { "`", "`", "\\" }, type = "string" }, + + { pattern = { "<", ">" }, type = "string" }, + { pattern = { "@", "%s" }, type = "string" }, + + { pattern = "//.*", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + + --{ pattern = {"link"}, type = "typst_underline" }, -- add underline text later + + -- Finish later + { pattern = "^%s*=+%s.+%f[\n]", type = "keyword" }, -- Bold + { pattern = {"%*_", "_%*"}, type = "keyword" }, -- Bold Italic + { pattern = {"_%*", "%*_"}, type = "keyword" }, -- Bold Italic + { pattern = {"_", "_"}, type = "keyword" }, -- Italic + { pattern = {"%*", "%*"}, type = "keyword2" }, -- Bold + + { pattern = "[%+%-\\/]", type = "operator" }, + { pattern = "\\[nrt]", type = "string" }, + { pattern = "\\u%b{}", type = "string" }, + { pattern = "\\.", type = "normal" }, + + }, + + symbols = {} +} + + + + + +syntax.add(typst_syntax) diff --git a/debian/extra/plugins/language_umka.lua b/debian/extra/plugins/language_umka.lua new file mode 100644 index 0000000..3575753 --- /dev/null +++ b/debian/extra/plugins/language_umka.lua @@ -0,0 +1,67 @@ +-- mod-version:3 +local syntax = require 'core.syntax' + +syntax.add { + name = "Umka", + files = { "%.um$" }, + comment = "//", + block_comment = { "/*", "*/" }, + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = "0x%x+", type = "number" }, + { pattern = "%d+%.?%d*[Ee]%-?%d+", type = "number" }, + { pattern = "%d+%.?%d*", type = "number" }, + { pattern = {'"', '"', '\\'}, type = "string" }, + { pattern = {"'", "'", '\\'}, type = "string" }, + + { pattern = ":=", type = "operator" }, + { pattern = "%.%.", type = "operator" }, + { pattern = "[%^%+%-%*/%%&|~<>!=]", type = "operator" }, + { pattern = "[%a_][%w_]*()%*?()%s*%f[%(]", type = {"function", "operator", "normal"} }, + { pattern = "%u[%w_]*", type = "literal" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + }, + symbols = { + ["break"] = "keyword", + ["case"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["default"] = "keyword", + ["else"] = "keyword", + ["for"] = "keyword", + ["fn"] = "keyword", + ["import"] = "keyword", + ["interface"] = "keyword", + ["if"] = "keyword", + ["in"] = "keyword", + ["map"] = "keyword", + ["return"] = "keyword", + ["str"] = "keyword", + ["struct"] = "keyword", + ["switch"] = "keyword", + ["type"] = "keyword", + ["var"] = "keyword", + ["weak"] = "keyword", + + -- types + ["void"] = "keyword2", + ["int8"] = "keyword2", + ["int16"] = "keyword2", + ["int32"] = "keyword2", + ["int"] = "keyword2", + ["uint8"] = "keyword2", + ["uint16"] = "keyword2", + ["uint32"] = "keyword2", + ["uint"] = "keyword2", + ["real32"] = "keyword2", + ["real"] = "keyword2", + ["bool"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + ["char"] = "keyword2", + ["fiber"] = "keyword2", + ["any"] = "keyword2", + ["null"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_v.lua b/debian/extra/plugins/language_v.lua new file mode 100644 index 0000000..d5b9764 --- /dev/null +++ b/debian/extra/plugins/language_v.lua @@ -0,0 +1,95 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "V", + files = { "%.v$", "%.vsh$" }, + headers = "^#!.*[ /]v\n", + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "`", "`", '\\' }, type = "string" }, + { pattern = { "r'", "'" }, type = "string" }, -- raw string single quotes + { pattern = { 'r"', '"' }, type = "string" }, -- raw string double quotes + { pattern = "0x[%da-fA-F_]+", type = "number" }, + { pattern = "0b[01_]+", type = "number" }, + { pattern = "00[01234567_]+", type = "number" }, + { pattern = "-?%.?%d+", type = "number" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%+%-%*%/%%%~%&%|%^%!%=]", type = "operator" }, + { pattern = "%:%=", type = "operator" }, + { pattern = "%.%.%.?", type = "operator" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "%$%s?[%a_][%w_]*", type = "keyword2" }, + { pattern = "%@%s?[%a_][%w_]*", type = "keyword2" }, + }, + symbols = { + ["as"] = "keyword", + ["asm"] = "keyword", + ["assert"] = "keyword", + ["atomic"] = "keyword", + ["break"] = "keyword", + ["const"] = "keyword", + ["continue"] = "keyword", + ["defer"] = "keyword", + ["else"] = "keyword", + ["enum"] = "keyword", + ["fn"] = "keyword", + ["for"] = "keyword", + ["go"] = "keyword", + ["goto"] = "keyword", + ["if"] = "keyword", + ["import"] = "keyword", + ["in"] = "keyword", + ["interface"] = "keyword", + ["is"] = "keyword", + ["isreftype"] = "keyword", + ["lock"] = "keyword", + ["match"] = "keyword", + ["module"] = "keyword", + ["mut"] = "keyword", + ["or"] = "keyword", + ["pub"] = "keyword", + ["return"] = "keyword", + ["rlock"] = "keyword", + ["select"] = "keyword", + ["shared"] = "keyword", + ["sizeof"] = "keyword", + ["static"] = "keyword", + ["struct"] = "keyword", + ["type"] = "keyword", + ["typeof"] = "keyword", + ["union"] = "keyword", + ["unsafe"] = "keyword", + ["__offsetof"] = "keyword", + + ["bool"] = "keyword2", + ["i8"] = "keyword2", + ["i16"] = "keyword2", + ["int"] = "keyword2", + ["i64"] = "keyword2", + ["i128"] = "keyword2", + ["u8"] = "keyword2", + ["u16"] = "keyword2", + ["u32"] = "keyword2", + ["u64"] = "keyword2", + ["u128"] = "keyword2", + ["f32"] = "keyword2", + ["f64"] = "keyword2", + ["byte"] = "keyword2", + ["char"] = "keyword2", + ["rune"] = "keyword2", + ["chan"] = "keyword2", + ["string"] = "keyword2", + ["map"] = "keyword2", + ["voidptr"] = "keyword2", + ["thread"] = "keyword2", + + ["true"] = "literal", + ["false"] = "literal", + ["none"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_wren.lua b/debian/extra/plugins/language_wren.lua new file mode 100644 index 0000000..35b8b8a --- /dev/null +++ b/debian/extra/plugins/language_wren.lua @@ -0,0 +1,52 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Wren", + files = { "%.wren$" }, + comment = "//", + block_comment = {"/*", "*/"}, + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = "%d+%.%d+[Ee]%d+", type = "number" }, + { pattern = "%d+%.%d+", type = "number" }, + { pattern = "%d+[Ee]%d+", type = "number" }, + { pattern = "0x%x+", type = "number" }, + { pattern = "%d+", type = "number" }, + { pattern = "%.%.%.?", type = "operator" }, + { pattern = "[<>!=]=", type = "operator" }, + { pattern = "|[^|]+|%s+", type = "string" }, + { pattern = "[%+%-=/%*%^%%<>!~|&?:]", type = "operator" }, + { pattern = "_[%w_]*", type = "keyword2" }, + { regex = [[\bFn.new\b]], type = "literal" }, + { pattern = "#!?%a[%w_]*%s*%(?[%w _,\"=]*%)?", type = "comment" }, + { pattern = "%a[%w_]*()%s+()is()%s+%a[%w_]*%s*%f[{]", type = {"function", "normal", "keyword", "normal"}}, + { pattern = "%a[%w_]*%s*=()%s*%f[(]", type = {"function", "normal"} }, + { pattern = "%a[%w_]*()%s*%f[({]", type = {"function", "normal"} }, + { pattern = "%a[%w_]+", type = "symbol" }, + }, + symbols = { + ["break"] = "keyword", + ["class"] = "keyword", + ["construct"] = "keyword", + ["continue"] = "keyword", + ["else"] = "keyword", + ["for"] = "keyword", + ["foreign"] = "keyword", + ["if"] = "keyword", + ["import"] = "keyword", + ["in"] = "keyword", + ["is"] = "keyword", + ["return"] = "keyword", + ["static"] = "keyword", + ["super"] = "keyword", + ["var"] = "keyword", + ["while"] = "keyword", + ["this"] = "keyword2", + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + }, +} diff --git a/debian/extra/plugins/language_yaml.lua b/debian/extra/plugins/language_yaml.lua new file mode 100644 index 0000000..8b7f634 --- /dev/null +++ b/debian/extra/plugins/language_yaml.lua @@ -0,0 +1,154 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +local yaml_bracket_list = { + patterns = { + -- comments + { pattern = { "#", "\n"}, type = "comment" }, + -- strings + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + -- keys + { + pattern = "[%w%d]+%g+()%s*():()%s", + type = { "keyword2", "normal", "operator", "normal" } + }, + -- variables + { pattern = "%$%a%w+", type = "keyword" }, + { pattern = "%$%{%{.-%}%}", type = "keyword" }, + -- numeric place holders + { pattern = "%-?%.inf", type = "number" }, + { pattern = "%.NaN", type = "number" }, + -- numbers + { pattern = "[%+%-]?0%d+", type = "number" }, + { pattern = "[%+%-]?0x%x+", type = "number" }, + { pattern = "[%+%-]?%d+[,%.eE:%+%d]*%d+", type = "number" }, + { pattern = "[%+%-]?%d+", type = "number" }, + -- others + { pattern = ",", type = "operator" }, + { pattern = "%w+", type = "string" }, + { + pattern = "[_%(%)%*@~`!%%%^&=%+%-\\;%.><%?/%s]+", + type = "string" + } + }, + symbols = {} +} + +syntax.add { + name = "YAML", + files = { "%.yml$", "%.yaml$" }, + comment = "#", + space_handling = false, + patterns = { + --- rules that start with spaces first and those taking precedence + -- parent and child keys + { + pattern = "^[%w%d]+%g+%s*%f[:]", + type = "literal" + }, + { + pattern = "^%s+[%w%d]+%g+%s*%f[:]", + type = "keyword2" + }, + -- bracket lists after key declaration + { + pattern = { ":%s+%[", "%]" }, + syntax = yaml_bracket_list, type = "operator" + }, + { + pattern = { ":%s+{", "}" }, + syntax = yaml_bracket_list, type = "operator" + }, + -- child key + { + pattern = "^%s+()[%w%d]+%g+()%s*():()%s", + type = { "normal", "keyword2", "normal", "operator", "normal" } + }, + -- child list element + { + pattern = "^%s+()%-()%s+()[%w%d]+%g+()%s*():()%s", + type = { "normal", "operator", "normal", "keyword2", "normal", "operator", "normal" } + }, + -- unkeyed bracket lists + { + pattern = { "^%s*%[", "%]" }, + syntax = yaml_bracket_list, type = "operator" + }, + { + pattern = { "^%s*{", "}" }, + syntax = yaml_bracket_list, type = "operator" + }, + { + pattern = { "^%s*%-%s*%[", "%]" }, + syntax = yaml_bracket_list, type = "operator" + }, + { + pattern = { "^%s*%-%s*{", "}" }, + syntax = yaml_bracket_list, type = "operator" + }, + -- rule to optimize space handling + { pattern = "%s+", type = "normal" }, + --- all the other rules + -- comments + { pattern = { "#", "\n"}, type = "comment" }, + -- strings + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + -- extra bracket lists rules on explicit type + { + pattern = { "!!%w+%s+%[", "%]"}, + syntax = yaml_bracket_list, type = "operator" + }, + { + pattern = { "!!%w+%s+{", "}"}, + syntax = yaml_bracket_list, type = "operator" + }, + -- numeric place holders + { pattern = "%-?%.inf", type = "number" }, + { pattern = "%.NaN", type = "number" }, + -- parent list element + { + pattern = "^%-()%s+()[%w%d]+%g+()%s*():()%s", + type = { "operator", "normal", "keyword2", "normal", "operator", "normal" } + }, + -- key label + { + pattern = "%&()%g+", + type = { "keyword", "literal" } + }, + -- key elements expansion + { pattern = "<<", type = "literal" }, + { + pattern = "%*()[%w%d_]+", + type = { "keyword", "literal" } + }, + -- explicit data types + { pattern = "!!%g+", type = "keyword" }, + -- parent key + { + pattern = "^[%w%d]+%g+()%s*():()%s", + type = { "literal", "normal", "operator", "normal" } + }, + -- variables + { pattern = "%$%a%w+", type = "keyword" }, + { pattern = "%$%{%{.-%}%}", type = "keyword" }, + -- numbers + { pattern = "[%+%-]?0%d+", type = "number" }, + { pattern = "[%+%-]?0x%x+", type = "number" }, + { pattern = "[%+%-]?%d+[,%.eE:%+%d]*%d+", type = "number" }, + { pattern = "[%+%-]?%d+", type = "number" }, + -- special operators + { pattern = "[%*%|%!>%%]", type = "keyword" }, + { pattern = "[%-%$:%?]+", type = "operator" }, + -- Everything else as a string + { pattern = "[%d%a_][%g_]*", type = "string" }, + { pattern = "%p+", type = "string" } + }, + symbols = { + ["true"] = "number", + ["false"] = "number", + ["y"] = "number", + ["n"] = "number" + } +} diff --git a/debian/extra/plugins/language_zig.lua b/debian/extra/plugins/language_zig.lua new file mode 100644 index 0000000..37a8fc4 --- /dev/null +++ b/debian/extra/plugins/language_zig.lua @@ -0,0 +1,118 @@ +-- mod-version:3 +local syntax = require "core.syntax" + +syntax.add { + name = "Zig", + files = { "%.zig$" }, + comment = "//", + patterns = { + { pattern = "//.-\n", type = "comment" }, + { pattern = "\\\\.-\n", type = "string" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "[iu][%d_]+", type = "keyword2" }, + { pattern = "0b[01_]+", type = "number" }, + { pattern = "0o[0-7_]+", type = "number" }, + { pattern = "0x[%x_]+", type = "number" }, + { pattern = "0x[%x_]+%.[%x_]*[pP][-+]?%d+", type = "number" }, + { pattern = "0x[%x_]+%.[%x_]*", type = "number" }, + { pattern = "0x%.[%x_]+[pP][-+]?%d+", type = "number" }, + { pattern = "0x%.[%x_]+", type = "number" }, + { pattern = "0x[%x_]+[pP][-+]?%d+", type = "number" }, + { pattern = "0x[%x_]+", type = "number" }, + { pattern = "%d[%d_]*%.[%d_]*[eE][-+]?%d+", type = "number" }, + { pattern = "%d[%d_]*%.[%d_]*", type = "number" }, + { pattern = "%d[%d_]*", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&%.%?]", type = "operator" }, + { pattern = "[%a_][%w_]*()%s*%(", type = {"function", "normal"} }, + { pattern = "[A-Z][%w_]*", type = "keyword2" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "@()[%a_][%w_]*", type = {"operator", "function"} }, + }, + symbols = { + ["fn"] = "keyword", + ["asm"] = "keyword", + ["volatile"] = "keyword", + ["continue"] = "keyword", + ["break"] = "keyword", + ["switch"] = "keyword", + ["for"] = "keyword", + ["while"] = "keyword", + ["var"] = "keyword", + ["anytype"] = "keyword", + ["anyframe"] = "keyword", + ["const"] = "keyword", + ["test"] = "keyword", + ["packed"] = "keyword", + ["extern"] = "keyword", + ["export"] = "keyword", + ["pub"] = "keyword", + ["defer"] = "keyword", + ["errdefer"] = "keyword", + ["align"] = "keyword", + ["usingnamespace"] = "keyword", + ["noasync"] = "keyword", + ["async"] = "keyword", + ["await"] = "keyword", + ["cancel"] = "keyword", + ["suspend"] = "keyword", + ["resume"] = "keyword", + ["threadlocal"] = "keyword", + ["linksection"] = "keyword", + ["callconv"] = "keyword", + ["try"] = "keyword", + ["catch"] = "keyword", + ["orelse"] = "keyword", + ["unreachable"] = "keyword", + ["error"] = "keyword", + ["if"] = "keyword", + ["else"] = "keyword", + ["return"] = "keyword", + ["comptime"] = "keyword", + ["stdcallcc"] = "keyword", + ["ccc"] = "keyword", + ["nakedcc"] = "keyword", + ["and"] = "keyword", + ["or"] = "keyword", + ["struct"] = "keyword", + ["enum"] = "keyword", + ["union"] = "keyword", + ["opaque"] = "keyword", + ["inline"] = "keyword", + ["allowzero"] = "keyword", + ["noalias"] = "keyword", + ["nosuspend"] = "keyword", + + -- types + ["f16"] = "keyword2", + ["f32"] = "keyword2", + ["f64"] = "keyword2", + ["f80"] = "keyword2", + ["f128"] = "keyword2", + ["void"] = "keyword2", + ["c_void"] = "keyword2", + ["isize"] = "keyword2", + ["usize"] = "keyword2", + ["c_short"] = "keyword2", + ["c_ushort"] = "keyword2", + ["c_int"] = "keyword2", + ["c_uint"] = "keyword2", + ["c_long"] = "keyword2", + ["c_ulong"] = "keyword2", + ["c_longlong"] = "keyword2", + ["c_ulonglong"] = "keyword2", + ["c_longdouble"] = "keyword2", + ["bool"] = "keyword2", + + ["noreturn"] = "keyword2", + ["type"] = "keyword2", + ["anyerror"] = "keyword2", + ["comptime_int"] = "keyword2", + ["comptime_float"] = "keyword2", + + ["true"] = "literal", + ["false"] = "literal", + ["null"] = "literal", + ["undefined"] = "literal", + }, +} diff --git a/debian/extra/plugins/lsp/LICENSE b/debian/extra/plugins/lsp/LICENSE new file mode 100644 index 0000000..d9692b8 --- /dev/null +++ b/debian/extra/plugins/lsp/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2021-2023 Jefferson González +Copyright (c) 2023-present Lite XL team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/debian/extra/plugins/lsp/README.md b/debian/extra/plugins/lsp/README.md new file mode 100644 index 0000000..387811a --- /dev/null +++ b/debian/extra/plugins/lsp/README.md @@ -0,0 +1,271 @@ +# LSP Plugin for Lite XL editor + +Plugin that provides intellisense for Lite XL by leveraging the [LSP protocol] +While still a work in progress it already implements all the most important +features to make your life easier while coding with Lite XL. Using it +requires __Lite XL v2.1+__ (for __Lite XL v2.0.1__ to __Lite XL v2.0.5__ +check out the __0.1__ branch). [lint+] is optionally used to render +diagnostic messages while you type so make sure to get it. Also, the +[snippets] plugin is used to properly process the received autocompletions +in the form of snippets, so grab that too. + +To use, clone this project into the __lsp__ directory in your plugins +folder. Finally you will need the [Widgets] lib so make sure to also drop +it into your lite-xl configs directory. For example: + +```sh +cd ~/.config/lite-xl/ +git clone https://github.com/lite-xl/lite-xl-lsp plugins/lsp +git clone https://github.com/lite-xl/lite-xl-widgets libraries/widget +git clone https://github.com/liquidev/lintplus plugins/lintplus +wget https://raw.githubusercontent.com/vqns/lite-xl-snippets/main/snippets.lua \ + -O plugins/snippets.lua +wget https://raw.githubusercontent.com/vqns/lite-xl-snippets/main/lsp_snippets.lua \ + -O plugins/lsp_snippets.lua +``` + +The lite-xl configs directory should have: + +* ~/.config/lite-xl/libraries/widget/ +* ~/.config/lite-xl/plugins/lsp/ +* ~/.config/lite-xl/plugins/lintplus/ +* ~/.config/lite-xl/plugins/snippets.lua +* ~/.config/lite-xl/plugins/lsp_snippets.lua + +## Features + +Stuff that is currently implemented: + +* Code auto completion (**ctrl+space**) +* Function signatures tooltip (**ctrl+shift+space**) +* Current cursor symbol details tooltip on mouse hover or shortcut (**alt+a**) +* Goto definition (**alt+d**) +* Goto implementation (**alt+shift+d**) +* View/jump to current document symbols (**alt+s**) +* Find workspace symbols (**alt+shift+s**) +* View/jump to symbol references (**alt+f**) +* View/jump to document diagnostic messages (**alt+e**) +* Document format (**alt+shift+f**) +* Optional diagnostics rendering while typing with [lint+] + (**alt+shift+e** to toggle) +* List all documents with diagnostics (**ctrl+alt+e**) +* Snippets processing using the [snippets] plugin + +## Setting a LSP Server + +The easiest method of setting up a lsp server is by using the __[config.lua]__ +file shipped with the lsp plugin which already contains a list of predefined +servers (notice: not all of them have been tested to work). Require this file +on your users **init.lua**, call `setup()` on the desired lsp servers or +overwrite the configuration options of the defined lsp servers if needed +as shown below: + +__Examples:__ + +```lua +local lspconfig = require "plugins.lsp.config" + +-- Activate clangd without overwriting any settings for c/c++ +-- autocompletion (requires a compile_commands.json file on +-- your project directory usually generated by build tools +-- like cmake or meson) +-- See: https://clangd.llvm.org/installation.html#project-setup +lspconfig.clangd.setup() + +-- Activate gopls +lspconfig.gopls.setup() + +-- Activate the lua-language-server, set the server command and +-- modify the default settings in order to disable diagnostics. +lspconfig.sumneko_lua.setup { + command = { + "/path/to/lua-language-server/bin/Linux/lua-language-server", + "-E", + "/path/to/lua-language-server/main.lua" + }, + settings = { + Lua = { + diagnostics = { + enable = false + } + } + } +} + +-- Activate intelephense and pass additional initializationOptions +-- like the license key and storage path. +lspconfig.intelephense.setup { + init_options = { + licenceKey = "MYLICENSEKEY", + storagePath = "/home/myuser/.cache/intelephense" + } +} +``` + +If your preferred LSP server is not listed on the config.lua file feel free +to submit a __pull request__ with the addition! + +## Manually Configuring a LSP Server + +Besides the __[config.lua]__ method, you can fully define an lsp server in +your user init.lua file. You would need to require the lsp plugin and use the +**add_server** function as shown on the following example: + +```lua +local lsp = require "plugins.lsp" + +lsp.add_server { + -- Name of server + name = "intelephense", + -- Main language + language = "PHP", + -- If the server supports multiple languages: + -- language = { + -- { id = "javascript", pattern = "%.js$" }, + -- { id = "typescript", pattern = "%.ts$" }, + -- } + -- If no pattern matches, the file extension is used instead. + -- File types that are supported by this server + file_patterns = { "%.php$" }, + -- LSP command and optional arguments + command = { "intelephense", "--stdio" }, + -- Optional table of settings to pass into the lsp + -- Note that also having a settings.json or settings.lua in + -- your workspace directory with a table of settings is supported. + settings = { + intelephense = { + files = { + exclude = { + "**/.git/**" + } + } + } + }, + -- Optional table of initializationOptions for the LSP + init_options = { + storagePath = "/home/myuser/.cache/intelephense" + }, + -- Set by default to 16 should only be modified if having issues with a server + requests_per_second = 16, + -- Some servers like bash language server support incremental changes + -- which are more performant but don't advertise it, set to true to force + -- incremental changes even if server doesn't advertise them. + incremental_changes = false, + -- True to debug the lsp client when developing it + verbose = false +} +``` + +## LSP Plugin Settings + +Configuration options that can be used to control the plugin behaviour: + +```lua +---Show a symbol hover information when mouse cursor is on top. +---@type boolean +config.plugins.lsp.mouse_hover = true + +---The amount of time in milliseconds before showing the tooltip. +---@type integer +config.plugins.lsp.mouse_hover_delay = 300 + +---Show diagnostic messages +---@type boolean +config.plugins.lsp.show_diagnostics = true + +---Stop servers that aren't needed by any of the open files +---@type boolean +config.plugins.lsp.stop_unneeded_servers = true + +---Set to a file path to log all json +---@type string +config.plugins.lsp.log_file = "" + +---Setting to true prettyfies json for more readability on the log +---but this setting will impact performance so only enable it when +---in need of easy to read json output when developing the plugin. +---@type boolean +config.plugins.lsp.prettify_json = false + +---Send a server stderr output to lite log +---@type boolean +config.plugins.lsp.log_server_stderr = false + +---Force verbosity off even if a server is configured with verbosity on +---@type boolean +config.plugins.lsp.force_verbosity_off = false + +---Yield when reading from LSP which may give you better UI responsiveness +---when receiving large responses, but will affect LSP performance. +---@type boolean +config.plugins.lsp.more_yielding = false +``` + +## TODO + +- [ ] Properly handle multiple opened project directories +- [ ] Handle window/showMessage, window/showMessageRequest, + $/progress, telemetry/event +- [x] Be able to search workspace symbols 'workspace/symbol' +- [ ] Completion preselectSupport (needs autocomplete plugin change) +- [ ] Add symbol renaming support 'textDocument/rename' +- [x] Add Snippets support (this will need a whole standalone [snippets] plugin). +- [x] Fix issues when parsing stdout from some lsp servers (really fixed?). +- [x] More improvements to autocomplete.lua plugin + - [x] Detect view edges and render to the most visible side + - [x] Description box, detect view width and expand accordingly + - [ ] Support for pre-selected item + - [ ] Be able to use a custom sorting field. +- [x] Add hover support for function arguments + - [x] Add custom tooltip that accents active parameter and signature +- [x] Figure out how to get an autocompletion item full documentation with +'completionItem/resolve' or any other in order to better populate +the new autocomplete item description +- [x] (we kill it) Detect if lsp server hangs and restart it (eg: clangd) +- [x] Exit LSP server if no open document needs it. +- [x] Add hover support for symbols +- [x] Generate list of current document symbols for easy document navigation +- [x] Goto definition + - [x] Display select box when more than one result +- [x] Show diagnostics on active document similar to the linter plugin. +- [x] Send incremental changes on textDocument/didChange notification + since sending the whole document content on big files is slow and bad. + + +## Screenshots + +Some images to easily visualize the progress :) + +### Completion +![Completion](screenshots/completion01.png) + +![Completion](screenshots/completion02.png) + +![Completion](screenshots/completion03.png) + +![Completion](screenshots/completion04.png) + +### Symbol hover +![Hover](screenshots/hover01.png) + +![Hover](screenshots/hover02.png) + +### Function signatures +![Signature](screenshots/signatures01.png) + +### Document symbols +![Doc Symbols](screenshots/docsym01.png) +![Doc Symbols](screenshots/docsym02.png) + +### Goto definition +![Goto Definition](screenshots/gotodef01.png) + +### Diagnostics rendering using Lint+ +![Diagnostics](screenshots/diagnostics01.png) + + +[LSP protocol]: https://microsoft.github.io/language-server-protocol/specifications/specification-current/ +[lint+]: https://github.com/liquidev/lintplus +[snippets]: https://github.com/vqns/lite-xl-snippets +[Widgets]: https://github.com/lite-xl/lite-xl-widgets +[config.lua]: config.lua diff --git a/debian/extra/plugins/lsp/config.lua b/debian/extra/plugins/lsp/config.lua new file mode 100644 index 0000000..8ab6e05 --- /dev/null +++ b/debian/extra/plugins/lsp/config.lua @@ -0,0 +1,1031 @@ +-- +-- A list of servers. +-- +-- Can be used by doing a 'local lspconfig = require "plugins.lsp.config"' +-- on your user init.lua, for more details check the README.md +-- +-- Servers taken from: +-- https://github.com/prabirshrestha/vim-lsp/wiki/Servers +-- https://github.com/mattn/vim-lsp-settings/tree/master/settings +-- + +local lsp = require "plugins.lsp" +local util = require "plugins.lsp.util" +local config = require "core.config" +local snippets = pcall(require, "plugins.snippets") and config.plugins.lsp.snippets + +---Options that can be passed to a LSP server to overwrite the defaults. +---@class lsp.config.options +--- +---Name of server. +---@field name string +---Main language, eg: C. +---Can be a string or a table. +---If the table is empty, the file extension will be used instead. +---The table should be an array of tables containing `id` and `pattern`. +---The `pattern` will be matched with the file path. +---Will use the `id` of the first `pattern` that matches. +---If no pattern matches, the file extension will be used instead. +---@field language string | lsp.server.languagematch[] +---File types that are supported by this server. +---@field file_patterns string[] +---LSP command and optional arguments. +---@field command table +---On Windows, avoid running the LSP server with cmd.exe. +---@field windows_skip_cmd? boolean +---Enviroment variables to set for the server command. +---@field env? table +---Seconds before closing the server when not needed anymore. +---@field quit_timeout? number +---Optional table of settings to pass into the LSP. +---Note that also having a settings.json or settings.lua in +---your workspace directory with a table of settings is supported. +---@field settings? table +---Optional table of initializationOptions for the LSP. +---@field init_options? table +---Optional table of capabilities that will be merged with our default one. +---@field custom_capabilities? table +---Function called when the server has been started. +---@field on_start? fun(server: lsp.server) +---Set by default to 16 should only be modified if having issues with a server. +---@field requests_per_second? integer +---Some servers like bash language server support incremental changes +---which are more performant but don't advertise it, set to true to force +---incremental changes even if server doesn't advertise them. +---@field incremental_changes? boolean +---Set to true to debug the lsp client when developing it. +---@field verbose? boolean + +---@class lsp.config.server +---Register the lsp server for usage. +---@field setup fun(options?:lsp.config.options) +---Get the default lsp server options. +---@field get_options fun():lsp.config.options + +---Helper to register a language server. +---@param options lsp.config.options +---@return lsp.config.server +local function add_lsp(options) + return { + setup = function(user_options) + local merged_options = util.deep_merge(options, user_options) + lsp.add_server(merged_options) + end, + get_options = function() + return options + end + } +end + +---List of predefined language servers that can be easily enabled at runtime. +---@class lsp.config +local lspconfig = {} + +-- NOTE: as of 15/05/2025, the LSP-server-specific naming conventions used here are described in https://github.com/neovim/nvim-lspconfig/blob/ac1dfbe3b60e5e23a2cff90e3bd6a3bc88031a57/CONTRIBUTING.md#walkthrough:~:text=When%20choosing%20a,(jsonnet_ls). + +---# Bash - bash_ls +--- __Status__: Works +--- __Site__: https://github.com/bash-lsp/bash-language-server +--- __Installation__: https://github.com/bash-lsp/bash-language-server?tab=readme-ov-file#installation +lspconfig.bash_ls = add_lsp { + name = "bash_ls", + language = "shellscript", + file_patterns = { "%.sh$" }, + command = { "bash-language-server", "start" }, + incremental_changes = true, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.bashls = lspconfig.bash_ls + +---# C/C++ - ccls +--- __Status__: Works +--- __Site__: https://github.com/MaskRay/ccls/ +--- __Installation__: https://github.com/MaskRay/ccls/wiki/Install +lspconfig.ccls = add_lsp { + name = "ccls", + language = { + { id = "c", pattern = "%.[ch]$" }, + { id = "cpp", pattern = "%.[ch]pp$" }, + { id = "cpp", pattern = "%.[CH]$" }, + { id = "cpp", pattern = "%.[ch]%+%+$" }, + }, + file_patterns = { + "%.c$", "%.h$", "%.inl$", "%.cpp$", "%.hpp$", + "%.cc$", "%.C$", "%.cxx$", "%.c++$", "%.hh$", + "%.H$", "%.hxx$", "%.h++$", "%.objc$", "%.objcpp$" + }, + command = { "ccls" }, + verbose = false +} + +---# C/C++ - clangd +--- __Status__: Works +--- __Site__: https://clangd.llvm.org/ +--- __Installation__: install the clang software package on your system +--- __Note__: See https://clangd.llvm.org/installation.html#project-setup +lspconfig.clangd = add_lsp { + name = "clangd", + language = { + { id = "c", pattern = "%.[ch]$" }, + { id = "cpp", pattern = "%.[ch]pp$" }, + { id = "cpp", pattern = "%.[CH]$" }, + { id = "cpp", pattern = "%.[ch]%+%+$" }, + }, + file_patterns = { + "%.c$", "%.h$", "%.inl$", "%.cpp$", "%.hpp$", + "%.cc$", "%.C$", "%.cxx$", "%.c++$", "%.hh$", + "%.H$", "%.hxx$", "%.h++$", "%.objc$", "%.objcpp$" + }, + command = { "clangd", "-background-index" }, + verbose = false +} + +---# Clojure - clojure_lsp +--- __Status__: Works +--- __Site__: https://clojure-lsp.github.io/ +--- __Installation__: https://clojure-lsp.github.io/clojure-lsp/installation/ +lspconfig.clojure_lsp = add_lsp { + name = "clojure_lsp", + language = "clojure", + file_patterns = { "%.clj$", "%.cljs$", "%.clc$", "%.edn$" }, + command = { "clojure-lsp" }, + verbose = false +} + +---# Crystal - crystalline +--- __Status__: Works +--- __Site__: https://github.com/elbywan/crystalline +--- __Installation__: https://github.com/elbywan/crystalline?tab=readme-ov-file#installation +lspconfig.crystalline = add_lsp { + name = "crystalline", + language = "crystal", + file_patterns = { "%.cr$" }, + command = { "crystalline", "--stdio" }, + verbose = false +} + +---# CSS - vscode_css_ls +--- __Status__: Works +--- __Site__: https://github.com/vscode-langservers/vscode-css-languageserver-bin +--- __Installation__: https://github.com/vscode-langservers/vscode-css-languageserver-bin?tab=readme-ov-file#installing +lspconfig.vscode_css_ls = add_lsp { + name = "vscode_css_ls", + language = "css", + file_patterns = { "%.css$", "%.less$", "%.sass$" }, + command = { + { + 'vscode-css-languageserver', + 'vscode-css-language-server', + 'css-languageserver' + }, + '--stdio' + }, + fake_snippets = true, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.cssls = lspconfig.vscode_css_ls + +---# C# - omnisharp +--- __Status__: Works, but freezes on large projects (https://github.com/ppy/osu.git) +--- __Site__: https://github.com/OmniSharp/omnisharp-roslyn +--- __Installation__: https://github.com/OmniSharp/omnisharp-roslyn?tab=readme-ov-file#downloading-omnisharp +lspconfig.omnisharp = add_lsp { + name = "omnisharp", + language = "csharp", + file_patterns = { "%.cs$" }, + command = { "omnisharp", "-lsp" }, + verbose = false +} + +---# D - serve_d +--- __Status__: Works +--- __Site__: https://github.com/Pure-D/serve-d +--- __Installation__: https://github.com/Pure-D/serve-d?tab=readme-ov-file#installation +lspconfig.serve_d = add_lsp { + name = "serve_d", + language = "d", + file_patterns = { "%.di?$" }, + command = { "serve-d" }, + verbose = false +} + +---# Dart - dartls +--- __Status__: Works +--- __Site__: https://github.com/dart-lang/sdk +--- __Installation__: Provided by dart sdk +lspconfig.dartls = add_lsp { + name = "dartls", + language = "dart", + file_patterns = { "%.dart$" }, + command = { "dart", "language-server", "--protocol=lsp" }, + verbose = false +} + +---# Deno - deno_ls +--- __Status__: Works +--- __Site__: https://deno.land/manual/advanced/language_server +--- __Installation__: Provided in Deno runtime +lspconfig.deno_ls = add_lsp { + name = "deno_ls", + language = { + { id = "javascript", pattern = "%.js$" }, + { id = "javascriptreact", pattern = "%.jsx$" }, + { id = "typescript", pattern = "%.ts$" }, + { id = "typescriptreact", pattern = "%.tsx$" }, + }, + file_patterns = { "%.[tj]s$", "%.[tj]sx$" }, + command = { "deno", "lsp" }, + verbose = false, + settings = { + deno = { + enable = true, + unstable = true, + config = "./deno.json", + importMap = "./import_map.json", + lint = true, + codeLens = { + implementations = true, + references = true, + test = true, + referencesAllFunctions = true + }, + suggest = { + names = true, + paths = true, + completeFunctionCalls = true, + imports = { + autoDiscover = true, + hosts = { + ["https://deno.land/"] = true, + ["https://nest.land/"] = true, + ["https://crux.land/"] = true + } + }, + autoImports = true + } + } + } +} +-- NOTE: for retro-compatibility +lspconfig.deno = lspconfig.deno_ls + +---# Dockerfile - dockerfile_ls_nodejs +--- __Status__: Untested +--- __Site__: https://github.com/rcjsuen/dockerfile-language-server-nodejs +--- __Installation__: https://github.com/rcjsuen/dockerfile-language-server?tab=readme-ov-file#installation-instructions +lspconfig.dockerfile_ls_nodejs = add_lsp { + name = "dockerfile_ls_nodejs", + language = "dockerfile", + file_patterns = { "Dockerfile$" }, + command = { "docker-langserver", "--stdio" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.dockerls = lspconfig.dockerfile_ls_nodejs + +---# Elixir - elixir_ls +--- __Status__: Works +--- __Site__: https://github.com/elixir-lsp/elixir-ls +--- __Installation__: https://github.com/elixir-lsp/elixir-ls?tab=readme-ov-file#detailed-installation-instructions +lspconfig.elixir_ls = add_lsp { + name = "elixir_ls", + language = "elixir", + file_patterns = { "%.ex$", "%.exs$" }, + command = { "elixir-ls" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.elixirls = lspconfig.elixir_ls + +---# Elm - elm_ls +--- __Status__: Works +--- __Site__: https://github.com/elm-tooling/elm-language-server +--- __Installation__: https://github.com/elm-tooling/elm-language-server?tab=readme-ov-file#installation +lspconfig.elm_ls = add_lsp { + name = "elm_ls", + language = "elm", + file_patterns = { "%.elm$" }, + command = { "elm-language-server" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.elmls = lspconfig.elm_ls + +---# Erlang - erlang_ls +--- __Status__: Works +--- __Site__: https://github.com/erlang-ls/erlang_ls +--- __Installation__: https://github.com/erlang-ls/erlang_ls?tab=readme-ov-file#quickstart +lspconfig.erlang_ls = add_lsp { + name = "erlang_ls", + language = "erlang", + file_patterns = { "%.erl$", "%.hrl$" }, + command = { "Erlang", "LS", "-t", "stdio" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.erlangls = lspconfig.erlang_ls + +---# Fennel - fennel_ls +--- __Status__: Works +--- __Site__: https://git.sr.ht/~xerool/fennel-ls +--- __Installation__: https://git.sr.ht/~xerool/fennel-ls/tree/main/docs/manual.md#installation +lspconfig.fennel_ls = add_lsp { + name = "fennel_ls", + language = "fennel", + file_patterns = { "%.fnl$" }, + command = { "fennel-ls" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.fennells = lspconfig.fennel_ls + +---# Fortran - fort_ls +--- __Status__: Works +--- __Site__: https://fortls.fortran-lang.org/index.html +--- __Installation__: https://fortls.fortran-lang.org/quickstart.html +lspconfig.fort_ls = add_lsp { + name = "fort_ls", + language = "fortran", + file_patterns = { "%.f$", "%.f90$", "%.f95$", "%.F$" }, + command = { "fortls", "--notify_init" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.fortls = lspconfig.fort_ls + +---# Gleam - gleam_ls +--- __Status__: Works (the gleam lsp itself acts kinda weird) +--- __Site__: https://gleam.run/ +--- __Installation__: Included with the gleam compiler binary +lspconfig.gleam_ls = add_lsp { + name = "gleam_ls", + language = "gleam", + file_patterns = { "%.gleam$" }, + command = { "gleam", "lsp" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.gleam = lspconfig.gleam_ls + +---# glsl - glsl_analyzer +--- __Status__: Works +--- __Site__: https://github.com/nolanderc/glsl_analyzer +--- __Installation__: https://github.com/nolanderc/glsl_analyzer?tab=readme-ov-file#installation +lspconfig.glsl_analyzer = add_lsp { + name = "glsl_analyzer", + language = "glsl", + file_patterns = { "%.glsl$" }, + command = { "glsl_analyzer" }, + verbose = false +} + +---# Go - gopls +--- __Status__: Works +--- __Site__: https://pkg.go.dev/golang.org/x/tools/gopls +--- __Installation__: https://pkg.go.dev/golang.org/x/tools/gopls#readme-installation +lspconfig.gopls = add_lsp { + name = "gopls", + language = "go", + file_patterns = { "%.go$" }, + command = { "gopls" }, + verbose = false +} + +---# Groovy - groovy_ls +--- __Status__: Untested +--- __Site__: https://github.com/prominic/groovy-language-server +--- __Installation__: either install from your OS's package manager or build from source +--- __Note__: how to build from source: https://github.com/GroovyLanguageServer/groovy-language-server?tab=readme-ov-file#build +lspconfig.groovy_ls = add_lsp { + name = "groovy_ls", + language = "groovy", + file_patterns = { "%.groovy$", "%.gvy$", "%.gy$", "%.gsh$" }, + -- command = { "java", "-jar", "/path/to/groovy-language-server-all.jar" }, + command = { "groovy-language-server" }, + verbose = false +} + +---# Haskell - haskell_ls +--- __Status__: Untested +--- __Site__: https://github.com/haskell/haskell-language-server +--- __Installation__: https://haskell-language-server.readthedocs.io/en/latest/installation.html +lspconfig.haskell_ls = add_lsp { + name = "haskell_ls", + language = "haskell", + file_patterns = { "%.hs$", "%.lhs$" }, + command = { "haskell-language-server-wrapper", "--lsp" }, + verbose = false +} + +---# HTML - vscode_html_ls +--- __Status__: Works +--- __Site__: https://github.com/vscode-langservers/vscode-html-languageserver-bin +--- __Installation__: https://github.com/vscode-langservers/vscode-html-languageserver-bin?tab=readme-ov-file#installing +lspconfig.vscode_html_ls = add_lsp { + name = "vscode_html_ls", + language = "html", + file_patterns = { "%.html$" }, + command = { + { + 'vscode-html-languageserver', + 'vscode-html-language-server', + 'html-languageserver' + }, + '--stdio' + }, + verbose = false +} + +---# Java - jdtls +--- __Status__: Works +--- __Site__: https://github.com/eclipse/eclipse.jdt.ls +--- __Installation__: https://github.com/eclipse-jdtls/eclipse.jdt.ls?tab=readme-ov-file#installation +lspconfig.jdtls = add_lsp { + name = "jdtls", + language = "java", + file_patterns = { "%.java$" }, + command = { "jdtls" }, + verbose = false +} + +---# Javascript - flow +--- __Status__: Untested +--- __Site__: https://flow.org/ +--- __Installation__: https://flow.org/en/docs/install/ +lspconfig.flow = add_lsp { + name = "flow", + language = "javascript", + file_patterns = { "%.js$", "%.jsx$" }, + command = { "flow", "lsp" }, + verbose = false +} + +---# Javascript - quick_lint_js +--- __Status__: Works +--- __Site__: https://github.com/quick-lint/quick-lint-js +--- __Installation__: https://github.com/quick-lint/quick-lint-js?tab=readme-ov-file#installing +lspconfig.quick_lint_js = add_lsp { + name = "quick_lint_js", + language = { + { id = "javascriptreact", pattern = "%.jsx$" }, + { id = "javascript", pattern = "%.js$" }, + { id = "typescriptdefinition", pattern = "%.d%.ts$" }, + { id = "typescriptsource", pattern = "%.ts$" }, + { id = "typescriptreact", pattern = "%.tsx$" }, + { id = "typescript", pattern = ".*" }, + }, + file_patterns = { "%.[mc]?jsx?$", "%.tsx?$" }, + command = { "quick-lint-js", "--lsp-server" }, + verbose = false +} + +---# JSON - vscode_json_ls +--- __Status__: Works +--- __Site__: https://www.npmjs.com/package/vscode-json-languageserver +--- __Installation__: https://www.npmjs.com/package/vscode-json-languageserver#integrate +lspconfig.vscode_json_ls = add_lsp { + name = "vscode_json_ls", + language = "json", + file_patterns = { "%.json$", "%.jsonc$" }, + command = { + { + 'vscode-json-languageserver', + 'vscode-json-language-server', + 'json-languageserver', + }, + '--stdio' + }, + verbose = false +} + +---# Kotlin - kotlin_ls +--- __Status__: Works +--- __Site__: https://github.com/fwcd/kotlin-language-server +--- __Installation__: https://github.com/fwcd/kotlin-language-server?tab=readme-ov-file#getting-started +lspconfig.kotlin_ls = add_lsp { + name = "kotlin_ls", + language = "kotlin", + file_patterns = { "%.kt$", "%.kts$", "%.ktm$" }, + command = { "kotlin-language-server" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.kotlin_language_server = lspconfig.kotlin_ls + +---# LaTeX - texlab +--- __Status__: Works +--- __Site__: https://github.com/latex-lsp/texlab +--- __Installation__: https://github.com/latex-lsp/texlab?tab=readme-ov-file#requirements +lspconfig.texlab = add_lsp { + name = "texlab", + language = "latex", + file_patterns = { "%.tex$", "%.bib$" , "%.dtx$", "%.sty$", "%.ins$", "%.cls$" }, + command = { "texlab" } +} + +---# Lua - lua_ls +--- __Status__: Works +--- __Site__: https://github.com/sumneko/lua-language-server +--- __Installation__: https://github.com/sumneko/lua-language-server/wiki/Build-and-Run-(Standalone) +lspconfig.lua_ls = add_lsp { + name = "lua_ls", + language = "lua", + file_patterns = { "%.lua$" }, + command = { "lua-language-server" }, + verbose = false, + settings = { + Lua = { + completion = { + enable = true, + callSnippet = snippets and "Replace" or "Disable", + keywordSnippet = snippets and "Replace" or "Disable" + }, + develop = { + enable = false, + debuggerPort = 11412, + debuggerWait = false + }, + diagnostics = { + enable = true, + }, + hover = { + enable = true, + viewNumber = true, + viewString = true, + viewStringMax = 1000 + }, + runtime = { + version = 'Lua 5.4', + path = { + "?.lua", + "?/init.lua", + "?/?.lua", + "/usr/share/5.4/?.lua", + "/usr/share/lua/5.4/?/init.lua" + } + }, + signatureHelp = { + enable = true + }, + workspace = { + library = { + DATADIR, + USERDIR + }, + maxPreload = 2000, + preloadFileSize = 1000 + }, + telemetry = { + enable = false + } + } + } +} + +---# Markdown - marksman +--- __Status__: Works +--- __Site__: https://github.com/artempyanykh/marksman +--- __Installation__: https://github.com/artempyanykh/marksman/blob/main/docs/install.md +lspconfig.marksman = add_lsp { + name = "marksman", + language = "markdown", + file_patterns = { "%.md$" }, + command = { "marksman" }, + verbose = false +} + +---# Nix - nil_ls +--- __Status__: Works +--- __Site__: https://github.com/oxalica/nil +--- __Installation__: https://github.com/oxalica/nil?tab=readme-ov-file#installation +lspconfig.nil_ls = add_lsp { + name = "nil_ls", + language = "nix", + file_patterns = { "%.nix$" }, + command = { "nil" }, + verbose = false +} + +---# Nim - nimlsp +--- __Status__: Works +--- __Site__: https://github.com/PMunch/nimlsp +--- __Installation__: https://github.com/PMunch/nimlsp?tab=readme-ov-file#installing-nimlsp +lspconfig.nimlsp = add_lsp { + name = "nimlsp", + language = "nim", + file_patterns = { "%.nim$" }, + command = { "nimlsp" }, + requests_per_second = 25, + incremental_changes = false, + verbose = false +} + +---# Ocaml - ocaml_lsp +--- __Status__: Reported working on https://github.com/jgmdev/lite-xl-lsp/issues/17 +--- __Site__: https://github.com/ocaml/ocaml-lsp +--- __Installation__: https://github.com/ocaml/ocaml-lsp#installation +lspconfig.ocaml_lsp = add_lsp { + name = "ocaml_lsp", + language = "ocaml", + file_patterns = { "%.ml$", "%.mli$" }, + command = { "ocamllsp" }, + verbose = false +} + +---# Odin - ols +--- __Status__: Works +--- __Site__: https://github.com/DanielGavin/ols +--- __Installation__: https://github.com/DanielGavin/ols?tab=readme-ov-file#installation +lspconfig.ols = add_lsp { + name = "ols", + language = "odin", + file_patterns = { "%.odin$" }, + command = { "ols" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.odinls = lspconfig.ols + +---# Perl - perlnavigator +--- __Status__: Works +--- __Site__: https://github.com/bscan/PerlNavigator +--- __Installation__: https://github.com/bscan/PerlNavigator?tab=readme-ov-file#installation-for-other-editors +lspconfig.perlnavigator = add_lsp { + name = "perlnavigator", + language = "perl", + file_patterns = { "%.pl$", "%.pm$" }, + command = { "perlnavigator" }, + settings = { + perlnavigator = { + -- The following setting is only needed if you want to set a custom perl path. It already defaults to "perl" + perlPath = "perl" + } + } +} + +---# PHP - intelephense +--- __Status__: Works +--- __Site__: https://github.com/bmewburn/intelephense-docs +--- __Installation__: https://github.com/bmewburn/intelephense-docs/blob/master/installation.md +lspconfig.intelephense = add_lsp { + name = "intelephense", + language = "php", + file_patterns = { "%.php$" }, + command = { "intelephense", "--stdio" }, + verbose = false +} + +---# Python - python_ls_palantir +--- __Status__: Works (deprecated in favor of python-lsp-server) +--- __Site__: https://github.com/palantir/python-language-server +--- __Installation__: https://github.com/palantir/python-language-server?tab=readme-ov-file#installation +lspconfig.python_ls_palantir = add_lsp { + name = "python_ls_palantir", + language = "python", + file_patterns = { "%.py$" }, + command = { "pyls" }, + verbose = false +} + +---# Python - python_ls +--- __Status__: Works +--- __Site__: https://github.com/python-lsp/python-lsp-server +--- __Installation__: https://github.com/python-lsp/python-lsp-server?tab=readme-ov-file#installation +lspconfig.python_ls = add_lsp { + name = "python_ls", + language = "python", + file_patterns = { "%.py$" }, + command = { "pylsp" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.pylsp = lspconfig.python_ls + +--# Python - basedpyright +--- __Status__: Works +--- __Site__: https://github.com/DetachHead/basedpyright +--- __Installation__: `pip install basedpyright` or `npm install -g basedpyright` +lspconfig.basedpyright = add_lsp { + name = "basedpyright", + language = "python", + file_patterns = { "%.py$" }, + command = { "basedpyright-langserver", "--stdio" }, + verbose = false +} + +--# Python - pyright +--- __Status__: Works +--- __Site__: https://github.com/microsoft/pyright +--- __Installation__: https://microsoft.github.io/pyright/#/installation +lspconfig.pyright = add_lsp { + name = "pyright", + language = "python", + file_patterns = { "%.py$" }, + command = { "pyright-langserver", "--stdio" }, + verbose = false +} + +--# Python- ruff +--- __Status__: Works +--- __Site__: https://github.com/astral-sh/ruff +--- __Installation__: `pip install ruff` or `uv tool install ruff` +lspconfig.ruff = add_lsp { + name = "ruff", + language = "python", + file_patterns = { "%.py$" }, + command = { "ruff", "server" }, + verbose = false +} + +---# R - r_ls +-- __Status__: Works +-- __Site__: https://github.com/REditorSupport/languageserver +-- __Installation__: https://github.com/REditorSupport/languageserver#installation +lspconfig.r_ls = add_lsp { + name = "r_ls", + language = "r", + file_patterns = { "%.r$", "%.R$" }, + command = {"R", "--slave", "-e", "languageserver::run()"}, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.rlanguageserver = lspconfig.r_ls + +---# Ruby - ruby_lsp +--- __Status__: Works +--- __Site__: https://github.com/Shopify/ruby-lsp +--- __Installation__: Use `rvm` to install a version of ruby and then use `gem install ruby-lsp` +--- __Note__: to ensure ruby-lsp works properly, read the following: https://shopify.github.io/ruby-lsp/editors.html +lspconfig.ruby_lsp = add_lsp { + name = "ruby_lsp", + language = "ruby", + file_patterns = { "%.rb$" }, + command = { 'ruby-lsp' }, + -- Use the command below if you want to run ruby_lsp with bundler + -- command = { 'bundler', 'exec', 'ruby-lsp'}, + incremental_changes = true, + init_options = { + enabledFeatures = { + "codeActions", + "completion", + "diagnostics", + "documentHighlights", + "documentLink", + "documentSymbols", + "foldingRanges", + "formatting", + "hover", + "inlayHint", + "onTypeFormatting", + "selectionRanges", + -- semanticHighlighting is not currently supported by Lite XL + -- "semanticHighlighting" + }, + -- enableExperimentalFeatures = true, + -- rubyVersionManager = "", + }, + verbose = false +} + +---# Ruby - solargraph +--- __Status__: Untested +--- __Site__: https://github.com/castwide/solargraph +--- __Installation__: https://github.com/castwide/solargraph?tab=readme-ov-file#installation +lspconfig.solargraph = add_lsp { + name = "solargraph", + language = "ruby", + file_patterns = { "%.rb$" }, + command = { "solargraph", "stdio" }, + verbose = false +} + +---# Rust - rust_ls +--- __Status__: Works +--- __Site__: https://github.com/rust-lang/rls +--- __Installation__: https://github.com/rust-lang/rls?tab=readme-ov-file#setup +lspconfig.rust_ls = add_lsp { + name = "rust_ls", + language = "rust", + file_patterns = { "%.rs$" }, + command = { "rls" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.rls = lspconfig.rust_ls + +---# Rust - rust_analyzer +--- __Status__: Works +--- __Site__: https://rust-analyzer.github.io/ +--- __Installation__: https://rust-analyzer.github.io/manual.html#installation +lspconfig.rust_analyzer = add_lsp { + name = "rust_analyzer", + language = "rust", + file_patterns = { "%.rs$" }, + command = { "rust-analyzer" }, + verbose = false +} + +---# Scala - metals +--- __Status__: Works +--- __Site__: https://scalameta.org/metals/ +--- __Installation__: https://scalameta.org/metals/docs#installation +lspconfig.metals = add_lsp { + name = "metals", + language = "scala", + file_patterns = { "%.scala$" }, + command = { "metals" }, + verbose = false +} + +---# SQL - sql_ls +--- __Status__: Works +--- __Site__: https://github.com/joe-re/sql-language-server +--- __Installation__: https://github.com/joe-re/sql-language-server?tab=readme-ov-file#installation--how-to-setup +lspconfig.sql_ls = add_lsp { + name = "sql_ls", + language = "sql", + file_patterns = { "%.sql$" }, + command = { "sql-language-server", "up", "--method", "stdio" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.sqlls = lspconfig.sql_ls + +---# Svelte - svelte_ls +--- __Status__: Works +--- __Site__: https://github.com/sveltejs/language-tools/tree/master/packages/language-server +--- __Installation__: `npm install -g svelte-language-server` +--- __Note__: https://github.com/sveltejs/language-tools/tree/master/packages/language-server#how-can-i-use-it +lspconfig.svelte_ls = add_lsp { + name = "svelte_ls", + language = "svelte", + file_patterns = { "%.svelte$" }, + command = { "svelteserver", "--stdio" }, + verbose = false +} + +---# Tailwind CSS - tailwind_css_ls +--- __Status__: Broken (freezes when writing class names inside html doc, requires new implementation of json.lua) +--- __Site__: https://github.com/tailwindlabs/tailwindcss-intellisense +--- __Installation__: https://github.com/tailwindlabs/tailwindcss-intellisense?tab=readme-ov-file#installation +lspconfig.tailwind_css_ls = add_lsp { + name = "tailwind_css_ls", + language = "html", + file_patterns = { "%.html$"}, + command = {"tailwindcss-language-server", "--stdio"}, + fake_snippets = true, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.tailwindcss = lspconfig.tailwind_css_ls + +---# TOML - taplo +--- __Status__: Works +--- __Site__: https://github.com/tamasfe/taplo +--- __Installation__: https://taplo.tamasfe.dev/cli/installation/binary.html +lspconfig.taplo = add_lsp { + name = "taplo", + language = "toml", + file_patterns = { "%.toml$" }, + command = { "taplo", "lsp", "stdio" }, + verbose = false +} + +---# Typescript - typescript_ls +--- __Status__: Works +--- __Site__: https://github.com/typescript-language-server/typescript-language-server +--- __Installation__: https://github.com/typescript-language-server/typescript-language-server?tab=readme-ov-file#installing +lspconfig.typescript_ls = add_lsp { + name = "typescript_ls", + language = { + { id = "javascript", pattern = "%.[cm]?js$" }, + { id = "javascriptreact", pattern = "%.jsx$" }, + { id = "typescript", pattern = "%.ts$" }, + { id = "typescriptreact", pattern = "%.tsx$" }, + }, + file_patterns = { "%.jsx?$", "%.[cm]js$", "%.tsx?$" }, + command = { "typescript-language-server", "--stdio" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.tsserver = lspconfig.typescript_ls + +---# Typst - typst_lsp +--- __Status: Works +--- __Site__: https://github.com/nvarner/typst-lsp +--- __Installation__: https://github.com/nvarner/typst-lsp?tab=readme-ov-file#installation-guide +lspconfig.typst_lsp = add_lsp { + name = "typst_lsp", + language = "typst", + file_patterns = { "%.typ$" }, + command = { "typst-lsp" }, + verbose = false, + settings = { + exportPdf = "never", -- Choose onType, onSave or never. + experimentalFormatterMode = "on" -- Choose on, or off + } +} + +---# Typst - tinymist +--- __Status: Works +--- __Site__: https://github.com/Myriad-Dreamin/tinymist +--- __Instalation__: https://github.com/Myriad-Dreamin/tinymist?tab=readme-ov-file#installation +lspconfig.tinymist = add_lsp { + name = "tinymist", + language = "typst", + file_patterns = { "%.typ$" }, + command = { "tinymist" }, + verbose = false +} + +---# V - v_analyzer +--- __Status__: Works +--- __Site__: https://github.com/vlang/v-analyzer +--- __Installation__: https://github.com/vlang/v-analyzer?tab=readme-ov-file#installation +lspconfig.v_analyzer = add_lsp { + name = "v_analyzer", + language = "v", + file_patterns = { "%.vv?$", "%.vsh$" }, + command = { "v-analyzer", "--stdio" }, + verbose = false +} + +---# V - v_ls +--- __Status__: doesn't respond to completion requests (no longer officially maintained in favor of v-analyzer) +--- __Site__: https://github.com/vlang/vls +--- __Installation__: https://github.com/vlang/vls?tab=readme-ov-file#installation +lspconfig.v_ls = add_lsp { + name = "v_ls", + language = "v", + file_patterns = { "%.vv?$", "%.vsh$" }, + command = { "vlang-vls" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.vls = lspconfig.v_ls + +---# Vala - vala_ls +--- __Status__: Works +--- __Site__: https://github.com/vala-lang/vala-language-server +--- __Installation__: https://github.com/vala-lang/vala-language-server?tab=readme-ov-file#installation +lspconfig.vala_ls = add_lsp { + name = "vala_ls", + language = "vala", + file_patterns = { "%.vala$" }, + command = { "vala-language-server" }, + verbose = false +} + +---# Vim - vim_ls +--- __Status__: Untested +--- __Site__: https://github.com/iamcco/vim-language-server +--- __Installation__: https://github.com/iamcco/vim-language-server?tab=readme-ov-file#install +lspconfig.vim_ls = add_lsp { + name = "vim_ls", + language = "vim", + file_patterns = { "%.vim$" }, + command = { "vim-language-server", "--stdio" }, + verbose = false +} + +---# XML - lemminx +--- __Status__: Works +--- __Site__: https://github.com/eclipse/lemminx +--- __Installation__: https://github.com/eclipse-lemminx/lemminx?tab=readme-ov-file#generating-a-native-binary +lspconfig.lemminx = add_lsp { + name = "lemminx", + language = "xml", + file_patterns = { "%.xml$" }, + command = { "lemminx" }, + verbose = false +} + +---# YAML - yaml_ls +--- __Status__: Untested +--- __Site__: https://github.com/redhat-developer/yaml-language-server +--- __Installation__: https://github.com/redhat-developer/yaml-language-server?tab=readme-ov-file#getting-started +lspconfig.yaml_ls = add_lsp { + name = "yaml_ls", + language = "yaml", + file_patterns = { "%.yml$", "%.yaml$" }, + command = { "yaml-language-server", "--stdio" }, + verbose = false +} +-- NOTE: for retro-compatibility +lspconfig.yamlls = lspconfig.yaml_ls + +---# Zig - zls +--- __Status__: Untested +--- __Site__: https://github.com/zigtools/zls +--- __Installation__: https://zigtools.org/zls/install/ +lspconfig.zls = add_lsp { + name = "zls", + language = "zig", + file_patterns = { "%.zig$" }, + command = { "zls" }, + verbose = false +} + +return lspconfig diff --git a/debian/extra/plugins/lsp/diagnostics.lua b/debian/extra/plugins/lsp/diagnostics.lua new file mode 100644 index 0000000..c06bec4 --- /dev/null +++ b/debian/extra/plugins/lsp/diagnostics.lua @@ -0,0 +1,311 @@ +-- Store diagnostic messages received by an LSP. +-- @copyright Jefferson Gonzalez +-- @license MIT + +local core = require "core" +local config = require "core.config" +local util = require "plugins.lsp.util" +local Timer = require "plugins.lsp.timer" + +---@class lsp.diagnostics +local diagnostics = {} + +---@class lsp.diagnostics.position +---@field line integer +---@field character integer + +---@class lsp.diagnostics.range +---@field start lsp.diagnostics.position +---@field end lsp.diagnostics.position + +---@class lsp.diagnostics.severity +---@field ERROR integer +---@field WARNING integer +---@field INFO integer +---@field HINT integer +diagnostics.severity = { + ERROR = 1, + WARNING = 2, + INFO = 3, + HINT = 4 +} + +---@alias lsp.diagnostics.severity_code +---|>`diagnostics.severity.ERROR` +---| `diagnostics.severity.WARNING` +---| `diagnostics.severity.INFO` +---| `diagnostics.severity.HINT` + +---@class lsp.diagnostics.code_description +---@field href string + +---@class lsp.diagnostics.tag +---@field UNNECESSARY integer +---@field DEPRECATED integer +diagnostics.tag = { + UNNECESSARY = 1, + DEPRECATED = 2 +} + +---@alias lsp.diagnostics.tag_code +---|>`diagnostics.tag.UNNECESSARY` +---| `diagnostics.tag.DEPRECATED` + +---@class lsp.diagnostics.location +---@field uri string +---@field range lsp.diagnostics.range + +---@class lsp.diagnostics.related_information +---@field location lsp.diagnostics.location +---@field message string + +---A diagnostic message. +---@class lsp.diagnostics.message +---@field range lsp.diagnostics.position +---@field severity? lsp.diagnostics.severity_code | integer +---@field code? integer | string +---@field codeDescription? lsp.diagnostics.code_description +---@field source? string +---@field message string +---@field tags? lsp.diagnostics.tag_code[] +---@field relatedInformation? lsp.diagnostics.related_information[] +---@field data? any + +---A diagnostic item. +---@class lsp.diagnostics.item +---@field filename string +---@field messages lsp.diagnostics.message[] + +---@type table +diagnostics.list = {} + +---@type integer +diagnostics.count = 0 + +-- Try to load lintplus plugin if available for diagnostics rendering +local lintplus_found, lintplus = nil, nil +if config.plugins.lintplus ~= false then + lintplus_found, lintplus = pcall(require, "plugins.lintplus") +end +local lintplus_kinds = { "error", "warning", "info", "hint" } + +---List of linplus coroutines to delay messages population +---@type table +local lintplus_delays = {} + +---Used to set proper diagnostic type on lintplus +---@type table +diagnostics.lintplus_kinds = lintplus_kinds + +---@type boolean +diagnostics.lintplus_found = lintplus_found + +---@param a lsp.diagnostics.message +---@param b lsp.diagnostics.message +local function sort_helper(a, b) + local a_severity = a.severity or diagnostics.severity.ERROR + local b_severity = b.severity or diagnostics.severity.ERROR + return a_severity < b_severity +end + +---Helper to catch some trange occurances where nil is given as filename +---@param filename string|nil +---@return string | nil +local function get_absolute_path(filename) + if not filename then + core.error( + "[LSP Diagnostics]: nil filename given", + tostring(filename) + ) + return nil + end + return core.project_absolute_path(filename) +end + +---Get the position of diagnostics associated to a file. +---@param filename string +---@return integer | nil +function diagnostics.get_index(filename) + ---@cast filename +nil + filename = get_absolute_path(filename) + if not filename then return nil end + for index, diagnostic in ipairs(diagnostics.list) do + if diagnostic.filename == filename then + return index + end + end + return nil +end + +---Get the diagnostics associated to a file. +---@param filename string +---@param severity? lsp.diagnostics.severity_code | integer +---@return lsp.diagnostics.message[] | nil +function diagnostics.get(filename, severity) + ---@cast filename +nil + filename = get_absolute_path(filename) + if not filename then return nil end + for _, diagnostic in ipairs(diagnostics.list) do + if diagnostic.filename == filename then + if not severity then return diagnostic.messages end + + local results = {} + for _, message in ipairs(diagnostic.messages) do + if (message.severity or diagnostics.severity.ERROR) == severity then + table.insert(results, message) + end + end + + return #results > 0 and results or nil + end + end + return nil +end + +---Adds a new list of diagnostics associated to a file replacing previous one. +---@param filename string +---@param messages lsp.diagnostics.message[] +---@return boolean +function diagnostics.add(filename, messages) + local index = diagnostics.get_index(filename) + + ---@cast filename +nil + filename = get_absolute_path(filename) + if not filename then return false end + + table.sort(messages, sort_helper) + + if not index then + diagnostics.count = diagnostics.count + 1 + table.insert(diagnostics.list, { + filename = filename, messages = messages + }) + else + diagnostics.list[index].messages = messages + end + + return true +end + +---Removes all diagnostics associated to a file. +---@param filename string +function diagnostics.clear(filename) + local index = diagnostics.get_index(filename) + + if index then + table.remove(diagnostics.list, index) + diagnostics.count = diagnostics.count - 1 + end +end + +---Get the amount of diagnostics associated to a file. +---@param filename string +---@param severity? lsp.diagnostics.severity_code | integer +function diagnostics.get_messages_count(filename, severity) + local index = diagnostics.get_index(filename) + + if not index then return 0 end + + if not severity then return #diagnostics.list[index].messages end + + local count = 0 + for _, message in ipairs(diagnostics.list[index].messages) do + if (message.severity or diagnostics.severity.ERROR) == severity then + count = count + 1 + end + end + + return count +end + +---@param doc core.doc +function diagnostics.lintplus_init_doc(doc) + if lintplus_found then + lintplus.init_doc(doc.filename, doc) + end +end + +---Remove registered diagnostics from lintplus for the given file or for +---all files if no filename is given. +---@param filename? string +---@param force boolean +function diagnostics.lintplus_clear_messages(filename, force) + if lintplus_found then + if + not force and lintplus_delays[filename] + and + lintplus_delays[filename]:running() + then + return + end + if filename then + lintplus.clear_messages(filename) + else + for fname, _ in pairs(lintplus.messages) do + if lintplus_delays[fname] then + lintplus_delays[fname]:stop() + lintplus_delays[fname] = nil + end + lintplus.clear_messages(fname) + end + end + end +end + +---@param filename string +function diagnostics.lintplus_populate(filename) + if lintplus_found then + diagnostics.lintplus_clear_messages(filename, true) + + if not filename then + for _, diagnostic in ipairs(diagnostics.list) do + local fname = core.normalize_to_project_dir(diagnostic.filename) + for _, message in pairs(diagnostic.messages) do + local line, col = util.toselection(message.range) + local text = message.message + local kind = lintplus_kinds[message.severity or diagnostics.severity.ERROR] + + lintplus.add_message(fname, line, col, kind, text) + end + end + else + local messages = diagnostics.get(filename) + if messages then + for _, message in pairs(messages) do + local line, col = util.toselection(message.range) + local text = message.message + local kind = lintplus_kinds[message.severity or diagnostics.severity.ERROR] + + lintplus.add_message( + core.normalize_to_project_dir(filename), + line, col, kind, text + ) + end + end + end + end +end + +---@param filename string +---@param user_typed boolean +function diagnostics.lintplus_populate_delayed(filename) + if lintplus_found then + if not lintplus_delays[filename] then + lintplus_delays[filename] = Timer( + config.plugins.lsp.diagnostics_delay or 500, + true + ) + lintplus_delays[filename].on_timer = function() + diagnostics.lintplus_populate(filename) + lintplus_delays[filename] = nil + end + lintplus_delays[filename]:start() + else + lintplus_delays[filename]:reset() + lintplus_delays[filename]:start() + end + end +end + + +return diagnostics diff --git a/debian/extra/plugins/lsp/fonts/README.md b/debian/extra/plugins/lsp/fonts/README.md new file mode 100644 index 0000000..450ea0c --- /dev/null +++ b/debian/extra/plugins/lsp/fonts/README.md @@ -0,0 +1,29 @@ +# Fonts used by the LSP Plugin + +This directory holds fonts to enhance the LSP expirience. They are +generated by copying only the desired glyphs from other known fonts +([Nerd Fonts](https://www.nerdfonts.com/)). + +## Requirements + +* Symbols-2048-em Nerd Font Complete Mono.ttf - symbols.ttf + +**Resources:** +* https://www.nerdfonts.com/font-downloads +* https://github.com/ryanoasis/nerd-fonts/releases/download/v3.0.0/NerdFontsSymbolsOnly.zip + +## How to generate + +Copy all the required base fonts into this directory and run: + +```sh +./generate-fonts.py +``` +or +```sh +fontforge -script generate-fonts.py +``` + +## Generated Fonts + +* `symbols.ttf` - LSP symbols font used as icons on the autocomplete plugin diff --git a/debian/extra/plugins/lsp/fonts/generate-fonts.py b/debian/extra/plugins/lsp/fonts/generate-fonts.py new file mode 100755 index 0000000..01b8365 --- /dev/null +++ b/debian/extra/plugins/lsp/fonts/generate-fonts.py @@ -0,0 +1,101 @@ +#!/usr/bin/fontforge -script +# +# Generates a small LSP symbol icons font using 'Symbols Nerd Font' +# +# Usage: +# fontforge -script generate-font.py +# +# References: +# https://www.nerdfonts.com/font-downloads +# https://github.com/ryanoasis/nerd-fonts/releases/download/v3.0.0/NerdFontsSymbolsOnly.zip +# +import fontforge + +# Define the path to the source font file +# Recommended font from the Symbols Nerd Font package is: +# Symbols-2048-em Nerd Font Complete Mono.ttf +src_font_path = "Symbols-2048-em Nerd Font Complete Mono.ttf" + +# List of symbols to copy +# The symbol mappings were taken from: +# * https://github.com/onsails/lspkind.nvim +# * https://github.com/TorchedSammy/lite-xl-lspkind +symbols = [ + # + # Nerdicons Preset + # + '', # 0xF77E Text + '', # 0xF6A6 Method + '', # 0xF794 Function + '', # 0xF423 Constructor + 'ﰠ', # 0xFC20 Field + '', # 0xF52A Variable + 'ﴯ', # 0xFD2F Class + '', # 0xF0E8 Interface + '', # 0xF487 Module + 'ﰠ', # 0xFC20 Property + '塞', # 0xF96C Unit + '', # 0xF89F Value + '', # 0xF15D Enum + '', # 0xF80A Keyword + '', # 0xF44F Snippet + '', # 0xF8D7 Color + '', # 0xF718 File + '', # 0xF706 Reference + '', # 0xF74A Folder + '', # 0xF15D EnumMember + '', # 0xF8FE Constant + 'פּ', # 0xFB44 Struct + '', # 0xF0E7 Event + '', # 0xF694 Operator + '', # 0xF128 Unknown + '', # TypeParameter + # + # Codicons Preset + # + '', # Text + '', # Method + '', # Function + '', # Constructor + '', # Field + '', # Variable + '', # Class + '', # Interface + '', # Module + '', # Property + '', # Unit + '', # Value + '', # Enum + '', # Keyword + '', # Snippet + '', # Color + '', # File + '', # Reference + '', # Folder + '', # EnumMember + '', # Constant + '', # Struct + '', # Event + '', # Operator + '', # Unknown + '' # TypeParameter +] + +# Convert symbols list to an integers list a.k.a. unicode values +unicode_values = [] +for char in symbols: + unicode_values.append(ord(char)) + +# Load the source font into FontForge +src_font = fontforge.open(src_font_path) + +# Remove unwanted glyph +src_font.selection.select(*unicode_values) +src_font.selection.invert() +src_font.clear() + +# Save as new font +src_font.fontname = "LSPSymbols" +src_font.familyname = "LSP Symbols" +src_font.fullname = "LSP Symbols" +src_font.generate("symbols.ttf") diff --git a/debian/extra/plugins/lsp/fonts/symbols.ttf b/debian/extra/plugins/lsp/fonts/symbols.ttf new file mode 100644 index 0000000..371c161 Binary files /dev/null and b/debian/extra/plugins/lsp/fonts/symbols.ttf differ diff --git a/debian/extra/plugins/lsp/helpdoc.lua b/debian/extra/plugins/lsp/helpdoc.lua new file mode 100644 index 0000000..42d7a07 --- /dev/null +++ b/debian/extra/plugins/lsp/helpdoc.lua @@ -0,0 +1,32 @@ +---@type core.doc +local Doc = require "core.doc" + +---A readonly core.doc. +---@class lsp.helpdoc : core.doc +local HelpDoc = Doc:extend() + +---Set the help text. +---@param text string +function HelpDoc:set_text(text) + self.lines = {} + local i = 1 + for line in text:gmatch("([^\n]*)\n?") do + if line:byte(-1) == 13 then + line = line:sub(1, -2) + self.crlf = true + end + table.insert(self.lines, line .. "\n") + self.highlighter.lines[i] = false + i = i + 1 + end + self:reset_syntax() +end + +function HelpDoc:raw_insert(...) end +function HelpDoc:raw_remove(...) end +function HelpDoc:load(...) end +function HelpDoc:reload() end +function HelpDoc:save(...) end + + +return HelpDoc diff --git a/debian/extra/plugins/lsp/init.lua b/debian/extra/plugins/lsp/init.lua new file mode 100644 index 0000000..7b38c3a --- /dev/null +++ b/debian/extra/plugins/lsp/init.lua @@ -0,0 +1,2604 @@ +--- mod-version:3 +-- +-- LSP client for lite-xl +-- @copyright Jefferson Gonzalez +-- @license MIT +-- +-- Note: Annotations syntax documentation which is supported by +-- https://github.com/sumneko/lua-language-server can be read here: +-- https://emmylua.github.io/annotation.html + +-- TODO Change the code to make it possible to use more than one LSP server +-- for a single file if possible and needed, for eg: +-- One lsp may not support goto definition but another one registered +-- for the current document filetype may do. + +local core = require "core" +local common = require "core.common" +local config = require "core.config" +local command = require "core.command" +local style = require "core.style" +local keymap = require "core.keymap" +local translate = require "core.doc.translate" +local autocomplete = require "plugins.autocomplete" +local Doc = require "core.doc" +local DocView = require "core.docview" +local StatusView = require "core.statusview" +local RootView = require "core.rootview" +local LineWrapping +-- If the lsp plugin is loaded from users init.lua it will load linewrapping +-- even if it was disabled from the settings ui, so we queue this check since +-- there is no way to automatically load settings ui before the user module. +core.add_thread(function() + if config.plugins.linewrapping or type(config.plugins.linewrapping) == "nil" then + LineWrapping = require "plugins.linewrapping" + end +end) + +local json = require "plugins.lsp.json" +local util = require "plugins.lsp.util" +local listbox = require "plugins.lsp.listbox" +local diagnostics = require "plugins.lsp.diagnostics" +local Server = require "plugins.lsp.server" +local Timer = require "plugins.lsp.timer" +local SymbolResults = require "plugins.lsp.symbolresults" +local MessageBox = require "libraries.widget.messagebox" +local snippets_found, snippets = pcall(require, "plugins.snippets") + +---@type lsp.helpdoc +local HelpDoc = require "plugins.lsp.helpdoc" + +-- +-- Plugin settings +-- + +---Configuration options for the LSP plugin. +---@class config.plugins.lsp +---Set to a file path to log all json +---@field log_file string +---Setting to true prettyfies json for more readability on the log +---but this setting will impact performance so only enable it when +---in need of easy to read json output when developing the plugin. +---@field prettify_json boolean +---Show a symbol hover information when mouse cursor is on top. +---@field mouse_hover boolean +---The amount of time in milliseconds before showing the tooltip. +---@field mouse_hover_delay integer +---Show diagnostic messages +---@field show_diagnostics boolean +---Amount of milliseconds to delay updating the inline diagnostics. +---@field diagnostics_delay number +---Wether to enable snippets processing. +---@field snippets boolean +---Stop servers that aren't needed by any of the open files +---@field stop_unneeded_servers boolean +---Send a server stderr output to lite log +---@field log_server_stderr boolean +---Force verbosity off even if a server is configured with verbosity on +---@field force_verbosity_off boolean +---Yield when reading from LSP which may give you better UI responsiveness +---when receiving large responses, but will affect LSP performance. +---@field more_yielding boolean +config.plugins.lsp = common.merge({ + mouse_hover = true, + mouse_hover_delay = 300, + show_diagnostics = true, + diagnostics_delay = 500, + snippets = true, + stop_unneeded_servers = true, + log_file = "", + prettify_json = false, + log_server_stderr = false, + force_verbosity_off = false, + more_yielding = false, + autostart_server = true, + -- The config specification used by the settings gui + config_spec = { + name = "Language Server Protocol", + { + label = "Mouse Hover", + description = "Show a symbol hover information when mouse cursor is on top.", + path = "mouse_hover", + type = "TOGGLE", + default = true + }, + { + label = "Mouse Hover Delay", + description = "The amount of time in milliseconds before showing the tooltip.", + path = "mouse_hover_delay", + type = "NUMBER", + default = 300, + min = 50, + max = 2000 + }, + { + label = "Diagnostics", + description = "Show inline diagnostic messages with lint+.", + path = "show_diagnostics", + type = "TOGGLE", + default = false + }, + { + label = "Diagnostics Delay", + description = "Amount of milliseconds to delay the update of inline diagnostics.", + path = "diagnostics_delay", + type = "NUMBER", + default = 500, + min = 100, + max = 10000 + }, + { + label = "Snippets", + description = "Snippets processing using lsp_snippets, may need a restart.", + path = "snippets", + type = "TOGGLE", + default = true + }, + { + label = "Autostart Server", + description = "Automatically start server when opening a file", + path = "autostart_server", + type = "TOGGLE", + default = true + }, + { + label = "Stop Servers", + description = "Stop servers that aren't needed by any of the open files.", + path = "stop_unneeded_servers", + type = "TOGGLE", + default = true + }, + { + label = "Log File", + description = "Absolute path to a '.log' file for logging all json.", + path = "log_file", + type = "FILE", + filters = {"%.log$"} + }, + { + label = "Prettify JSON", + description = "Prettify json for more readability but impacts performance.", + path = "prettify_json", + type = "TOGGLE", + default = false + }, + { + label = "Log Standard Error", + description = "Send a server stderr output to lite log.", + path = "log_server_stderr", + type = "TOGGLE", + default = false + }, + { + label = "Force Verbosity Off", + description = "Turn verbosity off even if a server is configured with verbosity on.", + path = "force_verbosity_off", + type = "TOGGLE", + default = false + }, + { + label = "More Yielding", + description = "Yield when reading from LSP which may give you better UI responsiveness.", + path = "more_yielding", + type = "TOGGLE", + default = false + } + } +}, config.plugins.lsp) + + +-- +-- Main plugin functionality +-- +local lsp = {} + +---List of registered servers +---@type table +lsp.servers = {} + +---List of running servers +---@type table +lsp.servers_running = {} + +---Flag that indicates if last autocomplete request was a trigger +---to prevent requesting another autocompletion request until the +---autocomplete box is hidden since some lsp servers loose context +---and return wrong results (eg: lua-language-server) +---@type boolean +lsp.in_trigger = false + +---Flag that indicates if the user typed something on the editor to try and +---call autocomplete only when neccesary. +---@type boolean +lsp.user_typed = false + +---Used on the hover timer to display hover info +---@class lsp.hover_position +---@field doc core.doc | nil +---@field x number +---@field y number +---@field triggered boolean +---@field utf8_range table | nil +lsp.hover_position = {doc = nil, x = -1, y = -1, triggered = false, utf8_range = nil} + +---@type lsp.timer +lsp.hover_timer = Timer(300, true) +lsp.hover_timer.on_timer = function() + local doc, line, col = lsp.get_hovered_location(lsp.hover_position.x, lsp.hover_position.y) + if not doc then return end + lsp.hover_position.triggered = true + lsp.hover_position.utf8_range = nil + lsp.hover_position.doc = doc + lsp.request_hover(doc, line, col) +end + +-- +-- Private functions +-- + +---Generate an lsp location object +---@param doc core.doc +---@param line integer +---@param col integer +local function get_buffer_position_params(doc, line, col) + return { + textDocument = { + uri = util.touri(core.project_absolute_path(doc.filename)), + }, + position = { + line = line - 1, + character = util.doc_utf8_to_utf16(doc, line, col) - 1 + } + } +end + +---Recursive function to generate a list of symbols ready +---to use for the lsp.request_document_symbols() action. +---@param list table +---@param parent? string +local function get_symbol_lists(list, parent) + local symbols = {} + local symbol_names = {} + parent = parent or "" + parent = #parent > 0 and (parent .. "/") or parent + + for _, symbol in pairs(list) do + -- Include symbol kind to be able to filter by it + local symbol_name = parent + .. symbol.name + .. "||" .. Server.get_symbol_kind(symbol.kind) + + table.insert(symbol_names, symbol_name) + + symbols[symbol_name] = { kind = symbol.kind } + + if symbol.location then + symbols[symbol_name].location = symbol.location + else + if symbol.range then + symbols[symbol_name].range = symbol.range + end + if symbol.uri then + symbols[symbol_name].uri = symbol.uri + end + end + + if symbol.children and #symbol.children > 0 then + local child_symbols, child_names = get_symbol_lists( + symbol.children, parent .. symbol.name + ) + + for _, name in pairs(child_names) do + table.insert(symbol_names, name) + symbols[name] = child_symbols[name] + end + end + end + + return symbols, symbol_names +end + +local function log(server, message, ...) + if server.verbose then + core.log("["..server.name.."] " .. message, ...) + else + core.log_quiet("["..server.name.."] " .. message, ...) + end +end + +---Check if active view is a DocView and return it +---@return core.docview|nil +local function get_active_docview() + local av = core.active_view + if getmetatable(av) == DocView and av.doc and av.doc.filename then + return av + end + return nil +end + +---Generates a code preview of a location +---@param location table +local function get_location_preview(location) + local line1, col1 = util.toselection( + location.range or location.targetRange + ) + local filename = core.normalize_to_project_dir( + util.tofilename(location.uri or location.targetUri) + ) + local abs_filename = core.project_absolute_path(filename) + + local file = io.open(abs_filename) + + if not file then + return "", filename .. ":" .. tostring(line1) .. ":" .. tostring(col1) + end + + local preview = "" + + -- sometimes the lsp can send the location of a definition where the + -- doc comments should be written but if no docs are written the line + -- is empty and subsequent line is the one we are interested in. + local line_count = 1 + for line in file:lines() do + if line_count >= line1 then + preview = line:gsub("^%s+", "") + :gsub("%s+$", "") + + if preview ~= "" then + break + else + -- change also the location table + if location.range then + location.range.start.line = location.range.start.line + 1 + location.range['end'].line = location.range['end'].line + 1 + elseif location.targetRange then + location.targetRange.start.line = location.targetRange.start.line + 1 + location.targetRange['end'].line = location.targetRange['end'].line + 1 + end + end + end + line_count = line_count + 1 + end + file:close() + + local position = filename .. ":" .. tostring(line1) .. ":" .. tostring(col1) + + return preview, position +end + +---Generate a list ready to use for the lsp.request_references() action. +---@param locations table +local function get_references_lists(locations) + local references, reference_names = {}, {} + + for _, location in pairs(locations) do + local preview, position = get_location_preview(location) + local name = preview .. "||" .. position + table.insert(reference_names, name) + references[name] = location + end + + return references, reference_names +end + +---Apply an lsp textEdit to a document if possible. +---@param server lsp.server +---@param doc core.doc +---@param text_edit table +---@param is_snippet boolean +---@param update_cursor_position boolean +---@return boolean True on success +local function apply_edit(server, doc, text_edit, is_snippet, update_cursor_position) + local range = nil + + if text_edit.range then + range = text_edit.range + elseif text_edit.insert then + range = text_edit.insert + elseif text_edit.replace then + range = text_edit.replace + end + + if not range then return false end + + local text = text_edit.newText + local line1, col1, line2, col2 + local current_text = "" + + if + not server.capabilities.positionEncoding + or + server.capabilities.positionEncoding == Server.position_encoding_kind.UTF16 + then + line1, col1, line2, col2 = util.toselection(range, doc) + else + line1, col1, line2, col2 = util.toselection(range) + core.error( + "[LSP] Unsupported position encoding: ", + server.capabilities.positionEncoding + ) + end + + if lsp.in_trigger then + local cline2, ccol2 = doc:get_selection() + local cline1, ccol1 = doc:position_offset(line2, col2, translate.start_of_word) + current_text = doc:get_text(cline1, ccol1, cline2, ccol2) + end + + doc:remove(line1, col1, line2, col2+#current_text) + + if is_snippet and snippets_found and config.plugins.lsp.snippets then + doc:set_selection(line1, col1, line1, col1) + snippets.execute {format = 'lsp', template = text} + return true + end + + doc:insert(line1, col1, text) + if update_cursor_position then + doc:move_to_cursor(nil, #text) + end + + return true +end + +---Callback given to autocomplete plugin which is executed once for each +---element of the autocomplete box which is hovered with the idea of providing +---better description of the selected element by requesting the LSP server for +---detailed information/documentation. +---@param index integer +---@param item table +local function autocomplete_onhover(index, item) + local completion_item = item.data.completion_item + + if item.data.server.verbose then + item.data.server:log( + "Resolve item: %s", util.jsonprettify(json.encode(completion_item)) + ) + end + + -- Only send resolve request if data field (which should contain + -- the item id) is available. + if completion_item.data then + item.data.server:push_request('completionItem/resolve', { + params = completion_item, + callback = function(server, response) + if response.result then + local symbol = response.result + if symbol.detail and #item.desc <= 0 then + item.desc = symbol.detail + end + if symbol.documentation then + if #item.desc > 0 then + item.desc = item.desc .. "\n\n" + end + if + type(symbol.documentation) == "table" + and + symbol.documentation.value + then + item.desc = item.desc .. symbol.documentation.value + if + symbol.documentation.kind + and + symbol.documentation.kind == "markdown" + then + item.desc = util.strip_markdown(item.desc) + end + else + item.desc = item.desc .. symbol.documentation + end + end + item.desc = item.desc:gsub("[%s\n]+$", "") + :gsub("^[%s\n]+", "") + :gsub("\n\n\n+", "\n\n") + if symbol.additionalTextEdits then + completion_item.additionalTextEdits = symbol.additionalTextEdits + end + + if server.verbose then + server:log( + "Resolve response: %s", util.jsonprettify(json.encode(symbol)) + ) + end + elseif server.verbose then + server:log("Resolve returned empty response") + end + end + }) + end +end + +---Callback that handles insertion of an autocompletion item that has +---the information of insertion +---@param index integer +---@param item table +local function autocomplete_onselect(index, item) + local completion = item.data.completion_item + local dv = get_active_docview() + local edit_applied = false + if completion.textEdit then + if dv then + local is_snippet = completion.insertTextFormat + and completion.insertTextFormat == Server.insert_text_format.Snippet + edit_applied = apply_edit(item.data.server, dv.doc, completion.textEdit, is_snippet, true) + if edit_applied then + -- Retrigger code completion if last char is a trigger + -- this is useful for example with clangd when autocompleting + -- a #include, if user types < a list of paths will appear + -- when selecting a path that ends with / as 0 then + -- TODO: do we need to sort this? Or is it expected to be already sorted? + -- TODO: are the edit ranges considered as if the "main" textEdit was applied already? + + -- Apply the edits in reverse order, so that their ranges are not shifted + -- around by previous edits + for i=#completion.additionalTextEdits,1,-1 do + local edit = completion.additionalTextEdits[i] + apply_edit(item.data.server, dv.doc, edit, false, false) + end + end + return edit_applied +end + +-- +-- Public functions +-- + +---Open a document location returned by LSP +---@param location table +function lsp.goto_location(location) + local doc_view = core.root_view:open_doc( + core.open_doc( + common.home_expand( + util.tofilename(location.uri or location.targetUri) + ) + ) + ) + local line1, col1 = util.toselection( + location.range or location.targetRange, doc_view.doc + ) + doc_view.doc:set_selection(line1, col1, line1, col1) +end + +lsp.get_location_preview = get_location_preview + +---Register an LSP server to be launched on demand +---@param options lsp.server.options +function lsp.add_server(options) + local required_fields = { + "name", "language", "file_patterns", "command" + } + + for _, field in pairs(required_fields) do + if not options[field] then + core.error( + "[LSP] You need to provide a '%s' field for the server.", + field + ) + return false + end + end + + if snippets_found and config.plugins.lsp.snippets then + options.snippets = true + end + + if #options.command <= 0 then + core.error("[LSP] Provide a command table list with the lsp command.") + return false + end + + -- On Windows using cmd.exe allows us to take advantage of its ability to run + -- the correct executable, as well as running scripts. + if PLATFORM == "Windows" and not options.windows_skip_cmd then + local escaped_commands = { } + if type(options.command) == "string" then + options.command = { options.command } + end + -- We need to escape `"` as `"""` + for _, v in ipairs(options.command) do + table.insert(escaped_commands, '"' .. string.gsub(v, '"', '"""') .. '"') + end + -- The result should be something like `cmd.exe /C ""first" "second" "third""` + options.command = 'cmd.exe /C "' .. table.concat(escaped_commands, " ") .. '"' + end + + if config.plugins.lsp.force_verbosity_off then + options.verbose = false + end + + lsp.servers[options.name] = options + + return true +end + +---Get valid running lsp servers for a given filename +---@param filename string +---@param initialized boolean +---@return table active_servers +function lsp.get_active_servers(filename, initialized) + local servers = {} + for name, server in pairs(lsp.servers) do + if common.match_pattern(filename, server.file_patterns) then + if lsp.servers_running[name] then + local add_server = true + if + initialized + and + ( + not lsp.servers_running[name].initialized + or + not lsp.servers_running[name].capabilities + ) + then + add_server = false + end + if add_server then + table.insert(servers, name) + end + end + end + end + return servers +end + +-- Used on lsp.get_workspace_settings() +local cached_workspace_settings = {} +local cached_workspace_settings_timestamp = 0 + +---Get table of configuration settings in the following way: +---1. Scan the USERDIR for .lite_lsp.lua or .lite_lsp.json (in that order) +---2. Merge server.settings +---4. Scan workspace if set also for .lite_lsp.lua/json and merge them or +---3. Scan server.path also for .lite_lsp.lua/json and merge them +---Note: settings are cached for 5 seconds for faster retrieval +--- on repetitive calls to this function. +---@param server lsp.server +---@param workspace? string +---@return table +function lsp.get_workspace_settings(server, workspace) + -- Search settings on the following directories, subsequent settings + -- overwrite the previous ones + local paths = { USERDIR } + local cached_index = USERDIR + local settings = {} + + if not workspace and server.path then + table.insert(paths, server.path) + cached_index = cached_index .. tostring(server.path) + elseif workspace then + table.insert(paths, workspace) + cached_index = cached_index .. tostring(workspace) + end + + if + cached_workspace_settings_timestamp > os.time() + and + cached_workspace_settings[cached_index] + then + return cached_workspace_settings[cached_index] + else + local position = 1 + for _, path in pairs(paths) do + if path then + local settings_new = nil + path = path:gsub("\\+$", ""):gsub("/+$", "") + if util.file_exists(path .. "/.lite_lsp.lua") then + local settings_lua = dofile(path .. "/.lite_lsp.lua") + if type(settings_lua) == "table" then + settings_new = settings_lua + end + elseif util.file_exists(path .. "/.lite_lsp.json") then + local file = io.open(path .. "/.lite_lsp.json", "r") + if file then + local settings_json = file:read("*a") + settings_new = json.decode(settings_json) + file:close() + end + end + + -- overwrite global settings by those specified in the server if any + if position == 1 and server.settings then + if settings_new then + settings_new = util.deep_merge(settings_new, server.settings) + else + settings_new = server.settings + end + end + + -- overwrite previous settings with new ones + if settings_new then + settings = util.deep_merge(settings, settings_new) + end + end + + position = position + 1 + end + + -- store settings on cache for 5 seconds for fast repeated calls + cached_workspace_settings[cached_index] = settings + cached_workspace_settings_timestamp = os.time() + 5 + end + + return settings +end + +-- TODO Update workspace folders of already running lsp servers if required +--- Start all applicable lsp servers for a given file. +--- @param filename string +--- @param project_directory string +function lsp.start_server(filename, project_directory) + for name, server in pairs(lsp.servers) do + if common.match_pattern(filename, server.file_patterns) then + if not lsp.servers_running[name] then + core.log("[LSP]: Starting " .. name) + ---@type boolean, lsp.server + local success, client = pcall(function() return Server(server) end) + if not success then + core.error("[LSP]: Unable to start %s:\nCommand: %s\nError: %s", name, common.serialize(server.command), client) + goto continue + end + client.yield_on_reads = config.plugins.lsp.more_yielding + + lsp.servers_running[name] = client + + -- We overwrite the default log function to log messages on lite + function client:log(message, ...) + core.log_quiet( + "[LSP/%s]: " .. message .. "\n", + self.name, + ... + ) + end + + function client:on_shutdown() + local sname = self.name + core.log( + "[LSP]: %s was shutdown, revise your configuration", + sname + ) + local last_shutdown = lsp.servers_running[sname].last_shutdown or 0 + lsp.servers_running = util.table_remove_key( + lsp.servers_running, + sname + ) + if system.get_time() - last_shutdown >= 5 then + lsp.start_servers() + if lsp.servers_running[sname] then + lsp.servers_running[sname].last_shutdown = system.get_time() + core.log( + "[LSP]: %s automatically restarted", + sname + ) + end + end + end + + -- Respond to workspace/configuration request + client:add_request_listener( + "workspace/configuration", + function(server, request) + local settings_default = lsp.get_workspace_settings(server) + + local settings_list = {} + for _, item in pairs(request.params.items) do + local value = nil + if item.section then + -- No workspace was specified so we return from default settings + if not item.scopeUri then + value = util.table_get_field(settings_default, item.section) + -- A workspace was specified so we return from that workspace + else + local settings_workspace = lsp.get_workspace_settings( + server, util.tofilename(item.scopeUri) + ) + value = util.table_get_field(settings_workspace, item.section) + end + + if not value then + server:log("Asking for '%s' config but not set", item.section) + else + server:log("Asking for '%s' config", item.section) + end + end + + table.insert(settings_list, value or json.null) + end + server:push_response(request.method, request.id, settings_list) + end + ) + + -- Respond to window/showDocument request + client:add_request_listener( + "window/showDocument", + function(server, request) + if request.params.external then + MessageBox.info( + server.name .. " LSP Server", + "Wants to externally open:\n'" .. request.params.uri .. "'", + function(_, button_id) + if button_id == 1 then + util.open_external(request.params.uri) + end + end, + MessageBox.BUTTONS_YES_NO + ) + else + local document = util.tofilename(request.params.uri) + ---@type core.docview + local doc_view = core.root_view:open_doc( + core.open_doc(common.home_expand(document)) + ) + if request.params.selection then + local line1, col1, line2, col2 = util.toselection( + request.params.selection, doc_view.doc + ) + doc_view.doc:set_selection(line1, col1, line2, col2) + end + if request.params.takeFocus then + system.raise_window() + end + end + + server:push_response(request.method, request.id, {success=true}) + end + ) + + -- Display server messages on lite UI + client:add_message_listener( + "window/logMessage", + function(server, params) + if core.log then + log(server, "%s", params.message) + end + end + ) + + -- Register/unregister diagnostic messages + client:add_message_listener( + "textDocument/publishDiagnostics", + function(server, params) + local abs_filename = util.tofilename(params.uri) + local filename = core.normalize_to_project_dir(abs_filename) + + if server.verbose then + core.log_quiet( + "["..server.name.."] %s diagnostics for: %s", + filename, + params.diagnostics and #params.diagnostics or 0 + ) + end + + if params.diagnostics and #params.diagnostics > 0 then + local added = diagnostics.add(filename, params.diagnostics) + + if + added and diagnostics.lintplus_found + and + config.plugins.lsp.show_diagnostics + and + util.doc_is_open(abs_filename) + then + -- we delay rendering of diagnostics for 2 seconds to prevent + -- the constant reporting of errors while typing. + diagnostics.lintplus_populate_delayed(filename) + end + else + diagnostics.clear(filename) + diagnostics.lintplus_clear_messages(filename) + end + end + ) + + -- Register/unregister diagnostic messages + client:add_message_listener( + "window/showMessage", + function(server, params) + local log_func = "log_quiet" + if params.type == Server.message_type.Error then + log_func = "error" + elseif params.type == Server.message_type.Warning then + log_func = "warn" + elseif params.type == Server.message_type.Info then + log_func = "log" + elseif params.type == Server.message_type.Debug then + log_func = "log_quiet" + end + core[log_func]("["..server.name.."] message: %s", params.message) + end + ) + + -- Send settings table after initialization if available. + client:add_event_listener("initialized", function(server) + if config.plugins.lsp.force_verbosity_off then + core.log_quiet("["..server.name.."] " .. "Initialized") + else + log(server, "Initialized") + end + local settings = lsp.get_workspace_settings(server) + if not util.table_empty(settings) then + server:push_notification("workspace/didChangeConfiguration", { + params = {settings = settings} + }) + end + + -- Send open document request if needed + for _, docu in ipairs(core.docs) do + if docu.filename then + if common.match_pattern(docu.filename, server.file_patterns) then + lsp.open_document(docu) + end + end + end + end) + + -- Start the server initialization process + client:initialize(project_directory, "Lite XL", VERSION) + end + end + ::continue:: + end +end + +---Stops all running servers. +function lsp.stop_servers() + for name, _ in pairs(lsp.servers) do + if lsp.servers_running[name] then + lsp.servers_running[name]:exit() + core.log("[LSP] stopped %s", name) + lsp.servers_running = util.table_remove_key(lsp.servers_running, name) + end + end +end + +---Start only the needed servers by current opened documents. +function lsp.start_servers() + for _, doc in ipairs(core.docs) do + if doc.filename then + lsp.start_server(doc.filename, core.project_dir) + end + end +end + +---Returns the hovered doc and the hovered position. +---Returns nil if no doc with an LSP activated is under the provided coordinates. +---@param x number +---@param y number +---@return core.doc|nil doc +---@return integer|nil line +---@return integer|nil col +function lsp.get_hovered_location(x, y) + local n = core.root_view.root_node:get_child_overlapping_point(x, y) + if not n then return end + local av = n.active_view + if not av:extends(DocView) then return end + if av and av.doc.lsp_open then + ---@type core.doc + local doc = av.doc + local line, col = av:resolve_screen_position(x, y) + local last_x = av:get_col_x_offset(line, #av.doc.lines[line]) + local lx, ly = av:get_line_screen_position(line) + if x > last_x + lx or y > ly + av:get_line_height() then return end + return doc, line, col + end +end + +---Send notification to applicable LSP servers that a document was opened +---@param doc core.doc +function lsp.open_document(doc) + -- in some rare ocassions this function may return nil when the + -- user closed lite-xl with files opened, removed the files from system + -- and opens lite-xl again which loads the non existent files. + local doc_path = core.project_absolute_path(doc.filename) + local file_info = system.get_file_info(doc_path) + if not file_info then + core.error("[LSP] could not open: %s", tostring(doc.filename)) + return + end + + local active_servers = lsp.get_active_servers(doc.filename, true) + + if #active_servers > 0 then + doc.disable_symbols = true -- disable symbol parsing on autocomplete plugin + for _, name in pairs(active_servers) do + local server = lsp.servers_running[name] + if server.capabilities.textDocumentSync.openClose then + if server.exit_timer then + server.exit_timer:stop() + server.exit_timer = nil + end + if file_info.size / 1024 <= 50 then + -- file size is in range so push the notification as usual. + server:push_notification('textDocument/didOpen', { + params = { + textDocument = { + uri = util.touri(doc_path), + languageId = server:get_language_id(doc), + version = doc.clean_change_id, + text = table.concat(doc.lines) + } + }, + callback = function() doc.lsp_open = true end + }) + else + -- big files too slow for json encoder, also sending a huge file + -- without yielding would stall the ui, and some lsp servers have + -- issues with receiving big files in a single chunk. + local text = table.concat(doc.lines) + :gsub('\\', '\\\\'):gsub("\n", "\\n"):gsub("\r", "\\r") + :gsub("\t", "\\t"):gsub('"', '\\"'):gsub('\b', '\\b') + :gsub('\f', '\\f') + + server:push_raw("textDocument/didOpen", { + raw_data = '{\n' + .. '"jsonrpc": "2.0",\n' + .. '"method": "textDocument/didOpen",\n' + .. '"params": {\n' + .. '"textDocument": {\n' + .. '"uri": "'..util.touri(doc_path)..'",\n' + .. '"languageId": "'..server:get_language_id(doc)..'",\n' + .. '"version": '..doc.clean_change_id..',\n' + .. '"text": "'..text..'"\n' + .. '}\n' + .. '}\n' + .. '}\n', + callback = function(server) + doc.lsp_open = true + log(server, "Big file '%s' ready for completion!", doc.filename) + end + }) + + log(server, "Processing big file '%s'...", doc.filename) + end + else + doc.lsp_open = true + end + end + end +end + +--- Send notification to applicable LSP servers that a document was saved +---@param doc core.doc +function lsp.save_document(doc) + if not doc.lsp_open then return end + + local active_servers = lsp.get_active_servers(doc.filename, true) + if #active_servers > 0 then + for _, name in pairs(active_servers) do + local server = lsp.servers_running[name] + local save = server.capabilities.textDocumentSync.save + if save then + -- Send document content only if required by lsp server + if save.includeText then + -- If save should include file content then raw is faster for + -- huge files that would take too much to encode. + local text = table.concat(doc.lines) + :gsub('\\', '\\\\'):gsub("\n", "\\n"):gsub("\r", "\\r") + :gsub("\t", "\\t"):gsub('"', '\\"'):gsub('\b', '\\b') + :gsub('\f', '\\f') + + server:push_raw("textDocument/didSave", { + raw_data = '{\n' + .. '"jsonrpc": "2.0",\n' + .. '"method": "textDocument/didSave",\n' + .. '"params": {\n' + .. '"textDocument": {\n' + .. '"uri": "'..util.touri(core.project_absolute_path(doc.filename))..'"\n' + .. '},\n' + .. '"text": "'..text..'"\n' + .. '}\n' + .. '}\n' + }) + else + server:push_notification('textDocument/didSave', { + params = { + textDocument = { + uri = util.touri(core.project_absolute_path(doc.filename)) + } + } + }) + end + end + end + end +end + +--- Send notification to applicable LSP servers that a document was closed +---@param doc core.doc +function lsp.close_document(doc) + if not doc.lsp_open then return end + + local active_servers = lsp.get_active_servers(doc.filename, true) + if #active_servers > 0 then + for _, name in pairs(active_servers) do + local server = lsp.servers_running[name] + if server.capabilities.textDocumentSync.openClose then + server:push_notification('textDocument/didClose', { + params = { + textDocument = { + uri = util.touri(core.project_absolute_path(doc.filename)), + languageId = server:get_language_id(doc), + version = doc.clean_change_id + } + } + }) + end + end + end +end + +--- Helper for lsp.update_document +---@param doc core.doc +local function request_signature_completion(doc) + local line1, col1, line2, col2 = doc:get_selection() + + if line1 == line2 and col1 == col2 then + -- First try to display a function signatures and if not possible + -- do normal code autocomplete + lsp.request_signature( + doc, + line1, + col1, + false, + lsp.request_completion + ) + end +end + +---Send document updates to applicable running LSP servers. +---@param doc core.doc +---@param request_completion? boolean +function lsp.update_document(doc, request_completion) + if not doc.lsp_open or not doc.lsp_changes or util.table_empty(doc.lsp_changes) then + return + end + + for _, name in pairs(lsp.get_active_servers(doc.filename, true)) do + local server = lsp.servers_running[name] + if not doc.lsp_changes[server] or #doc.lsp_changes[server] <= 0 then + goto continue + end + local sync_kind = server.capabilities.textDocumentSync.change + if + sync_kind ~= Server.text_document_sync_kind.None + and + server:can_push() -- ensure we don't loose incremental changes + then + local completion_callback = nil + if request_completion then + completion_callback = function() request_signature_completion(doc) end + end + + if + sync_kind == Server.text_document_sync_kind.Full + and + not server.incremental_changes + then + -- If sync should be done by sending full file content then lets do + -- it raw which is faster for big files. + local text = table.concat(doc.lines) + :gsub('\\', '\\\\'):gsub("\n", "\\n"):gsub("\r", "\\r") + :gsub("\t", "\\t"):gsub('"', '\\"'):gsub('\b', '\\b') + :gsub('\f', '\\f') + + server:push_raw("textDocument/didChange", { + overwrite = true, + raw_data = '{\n' + .. '"jsonrpc": "2.0",\n' + .. '"method": "textDocument/didChange",\n' + .. '"params": {\n' + .. '"textDocument": {\n' + .. '"uri": "'..util.touri(core.project_absolute_path(doc.filename))..'",\n' + .. '"version": '..doc.lsp_version .. "\n" + .. '},\n' + .. '"contentChanges": [\n' + .. '{"text": "'..text..'"}\n' + .. "]\n" + .. '}\n' + .. '}\n', + callback = function() + doc.lsp_changes[server] = nil + if completion_callback then + completion_callback() + end + end + }) + else + lsp.servers_running[name]:push_notification('textDocument/didChange', { + overwrite = true, + params = { + textDocument = { + uri = util.touri(core.project_absolute_path(doc.filename)), + version = doc.lsp_version, + }, + contentChanges = doc.lsp_changes[server] + }, + callback = function() + doc.lsp_changes[server] = nil + if completion_callback then + completion_callback() + end + end + }) + end + end + ::continue:: + end +end + +--- Enable or disable diagnostic messages +function lsp.toggle_diagnostics() + config.plugins.lsp.show_diagnostics = not config.plugins.lsp.show_diagnostics + + if not config.plugins.lsp.show_diagnostics then + diagnostics.lintplus_clear_messages() + core.log("[LSP] Diagnostics disabled") + else + diagnostics.lintplus_populate() + core.log("[LSP] Diagnostics enabled") + end +end + +--- Send to applicable LSP servers a request for code completion +function lsp.request_completion(doc, line, col, forced) + if lsp.in_trigger or not doc.lsp_open then + return + end + + for _, name in pairs(lsp.get_active_servers(doc.filename, true)) do + local server = lsp.servers_running[name] + if server.capabilities.completionProvider then + local capabilities = lsp.servers_running[name].capabilities + local char = doc:get_char(line, col-1) + local trigger_char = false + + local request = get_buffer_position_params(doc, line, col) + + -- without providing context some language servers like the + -- lua-language-server behave poorly and return garbage. + if + capabilities.completionProvider.triggerCharacters + and + #capabilities.completionProvider.triggerCharacters > 0 + and + char:match("%p") + and + util.intable(char, capabilities.completionProvider.triggerCharacters) + then + request.context = { + triggerKind = Server.completion_trigger_Kind.TriggerCharacter, + triggerCharacter = char + } + trigger_char = true; + end + + if + not trigger_char + and + not autocomplete.can_complete() + and + not forced + then + return false + end + + server:push_request('textDocument/completion', { + params = request, + overwrite = true, + callback = function(server, response) + lsp.user_typed = false + + -- don't autocomplete if caret position changed + local cline, cchar = doc:get_selection() + if cline ~= line or cchar ~= col then + return + end + + if server.verbose then + server:log( + "Completion response received." + ) + end + + if not response.result then + return + end + + local result = response.result + local complete_result = true + if result.isIncomplete then + if server.verbose then + core.log_quiet( + "["..server.name.."] " .. "Completion list incomplete" + ) + end + complete_result = false + end + + if not result.items or #result.items <= 0 then + -- Workaround for some lsp servers that don't return results + -- in the items property but instead on the results it self + if #result > 0 then + local items = result + result = {items = items} + else + return + end + end + + local symbols = { + name = lsp.servers_running[name].name, + files = lsp.servers_running[name].file_patterns, + items = {} + } + + local symbol_count = 1 + for _, symbol in ipairs(result.items) do + local label = symbol.label + or ( + symbol.textEdit + and symbol.textEdit.newText + or symbol.insertText + ) + + local info = server.get_completion_item_kind(symbol.kind) + + local desc = symbol.detail or "" + + -- TODO: maybe we should give priority to insertText above + if + symbol.label and + symbol.insertText and + #symbol.label > #symbol.insertText + then + label = symbol.insertText + if symbol.label ~= label then + desc = symbol.label + end + if symbol.detail then + desc = desc .. ": " .. symbol.detail + end + end + + if desc ~= "" then + desc = desc .. "\n" + end + + if + type(symbol.documentation) == "table" + and + symbol.documentation.value + then + desc = desc .. "\n" .. symbol.documentation.value + if + symbol.documentation.kind + and + symbol.documentation.kind == "markdown" + then + desc = util.strip_markdown(desc) + if symbol_count % 10 == 0 then + coroutine.yield() + end + end + elseif symbol.documentation then + desc = desc .. "\n" .. symbol.documentation + end + + desc = desc:gsub("[%s\n]+$", "") + :gsub("\n\n\n+", "\n\n") + + symbols.items[label] = { + info = info, + desc = desc, + data = { + server = server, completion_item = symbol + }, + onselect = autocomplete_onselect + } + + if + server.capabilities.completionProvider.resolveProvider + and + not symbol.documentation + then + symbols.items[label].onhover = autocomplete_onhover + end + + symbol_count = symbol_count + 1 + end + + if trigger_char and complete_result then + lsp.in_trigger = true + autocomplete.complete(symbols, function() + lsp.in_trigger = false + end) + else + autocomplete.complete(symbols) + end + end + }) + end + end +end + +--- Send to applicable LSP servers a request for info about a function +--- signatures and display them on a tooltip. +function lsp.request_signature(doc, line, col, forced, fallback) + if not doc.lsp_open then return end + + local char = doc:get_char(line, col-1) + local prev_char = doc:get_char(line, col-2) -- to support ', ' + for _, name in pairs(lsp.get_active_servers(doc.filename, true)) do + local server = lsp.servers_running[name] + if + server.capabilities.signatureHelpProvider + and + ( + forced + or + ( + server.capabilities.signatureHelpProvider.triggerCharacters + and + #server.capabilities.signatureHelpProvider.triggerCharacters > 0 + and + ( + util.intable( + char, server.capabilities.signatureHelpProvider.triggerCharacters + ) + or + util.intable( + prev_char, + server.capabilities.signatureHelpProvider.triggerCharacters + ) + ) + ) + ) + then + server:push_request('textDocument/signatureHelp', { + params = get_buffer_position_params(doc, line, col), + overwrite = true, + callback = function(server, response) + -- don't show signature if caret position changed + local cline, cchar = doc:get_selection() + if cline ~= line or cchar ~= col then + return + end + + if + response.result + and + response.result.signatures + and + #response.result.signatures > 0 + then + autocomplete.close() + listbox.show_signatures(response.result) + lsp.user_typed = false + elseif fallback then + fallback(doc, line, col) + end + end + }) + break + elseif fallback then + fallback(doc, line, col) + end + end +end + +---Returns the "selection" for the token that includes the provided position. +---@param doc core.doc +---@param line integer +---@param col integer +---@return integer line1 +---@return integer col2 +---@return integer line2 +---@return integer col2 +local function get_token_range(doc, line, col) + local col1 = 0 + for _, _, text in doc.highlighter:each_token(line) do + local text_len = #text + local col2 = col1 + text_len + if col2 >= col then + return line, col1 + 1, line, col2 + 1 + end + col1 = col2 + end + return line, col, line, col+1 +end + +---@type core.node +local help_active_node = nil +---@type core.node +local help_bottom_node = nil +--- Sends a request to applicable LSP servers for information about the +--- symbol where the cursor is placed and shows it on a tooltip. +function lsp.request_hover(doc, line, col, in_tab) + if not doc.lsp_open then return end + + for _, name in pairs(lsp.get_active_servers(doc.filename, true)) do + local server = lsp.servers_running[name] + if server.capabilities.hoverProvider then + server:push_request('textDocument/hover', { + params = get_buffer_position_params(doc, line, col), + callback = function(server, response) + if response.result and response.result.contents then + local range = response.result.range + local line1, col1, line2, col2 + if range then + line1, col1, line2, col2 = util.toselection(range, doc) + else + line1, col1, line2, col2 = get_token_range(doc, line, col) + end + lsp.hover_position.utf8_range = { line1 = line1, col1 = col1, + line2 = line2, col2 = col2 } + + local content = response.result.contents + local kind = nil + local text = "" + if type(content) == "table" then + if content.value then + text = content.value + if content.kind then kind = content.kind end + else + local texts = {} + for _, element in pairs(content) do + if type(element) == "string" then + table.insert(texts, element) + elseif type(element) == "table" and element.value then + table.insert(texts, element.value) + if not kind and element.kind then kind = element.kind end + end + end + text = table.concat(texts, "\n\n") + end + else -- content should be a string + text = content + end + if text and #text > 0 then + text = text:gsub("^[\n%s]+", ""):gsub("[\n%s]+$", "") + if not in_tab then + if kind == "markdown" then text = util.strip_markdown(text) end + listbox.show_text( + text, + { line = line, col = col } + ) + else + local line1, col1 = translate.start_of_word(doc, line, col) + local line2, col2 = translate.end_of_word(doc, line1, col1) + local title = doc:get_text(line1, col1, line2, col2):gsub("%s*", "") + title = "Help:" .. title .. ".md" + ---@type lsp.helpdoc + local helpdoc = HelpDoc(title, title) + helpdoc:set_text(text) + local helpview = DocView(helpdoc) + helpview.context = "application" + helpview.wrapping_enabled = true + if LineWrapping then + LineWrapping.update_docview_breaks(helpview) + end + if + not help_bottom_node + or + ( + #help_bottom_node.views == 1 + and + not help_active_node:get_node_for_view(help_bottom_node.views[1]) + ) + then + help_active_node = core.root_view:get_active_node_default() + help_bottom_node = help_active_node:split("down", helpview) + else + help_bottom_node:add_view(helpview) + end + end + end + end + end + }) + break + end + end +end + +--- Sends a request to applicable LSP servers for a symbol references +function lsp.request_references(doc, line, col) + if not doc.lsp_open then return end + + for _, name in pairs(lsp.get_active_servers(doc.filename, true)) do + local server = lsp.servers_running[name] + if server.capabilities.hoverProvider then + local request_params = get_buffer_position_params(doc, line, col) + request_params.context = {includeDeclaration = true} + server:push_request('textDocument/references', { + params = request_params, + callback = function(server, response) + if response.result and #response.result > 0 then + local references, reference_names = get_references_lists(response.result) + core.command_view:enter("Filter References", { + submit = function(text, item) + if item then + local reference = references[item.name] + lsp.goto_location(reference) + end + end, + suggest = function(text) + local res = common.fuzzy_match(reference_names, text) + for i, name in ipairs(res) do + local reference_info = util.split(name, "||") + res[i] = { + text = reference_info[1], + info = reference_info[2], + name = name + } + end + return res + end + }) + else + core.log("[LSP] No references found.") + end + end + }) + break + end + break + end +end + +---Sends a request to applicable LSP servers to retrieve the +---hierarchy of calls for the given function under the cursor. +function lsp.request_call_hierarchy(doc, line, col) + if not doc.lsp_open then return end + + for _, name in pairs(lsp.get_active_servers(doc.filename, true)) do + local server = lsp.servers_running[name] + if server.capabilities.callHierarchyProvider then + server:push_request('textDocument/prepareCallHierarchy', { + params = get_buffer_position_params(doc, line, col), + callback = function(server, response) + if response.result and #response.result > 0 then + -- TODO: Finish implement call hierarchy functionality + return + end + end + }) + return + end + end + + core.log("[LSP] Call hierarchy not supported.") +end + +---Sends a request to applicable LSP servers to rename a symbol. +---@param doc core.doc +---@param line integer +---@param col integer +---@param new_name string +function lsp.request_symbol_rename(doc, line, col, new_name) + if not doc.lsp_open then return end + + local servers_found = false + for _, name in pairs(lsp.get_active_servers(doc.filename, true)) do + servers_found = true + local server = lsp.servers_running[name] + if server.capabilities.renameProvider then + local request_params = get_buffer_position_params(doc, line, col) + request_params.newName = new_name + server:push_request('textDocument/rename', { + params = request_params, + callback = function(server, response) + if response.result and #response.result.changes then + for file_uri, changes in pairs(response.result.changes) do + core.log(file_uri .. " " .. #changes) + -- TODO: Finish implement textDocument/rename + end + end + + core.log("%s", json.prettify(json.encode(response))) + end + }) + return + end + end + + if not servers_found then + core.log("[LSP] " .. "No server ready or running") + else + core.log("[LSP] " .. "Symbols rename not supported") + end +end + +---Sends a request to applicable LSP servers to search for symbol on workspace. +---@param doc core.doc +---@param symbol string +function lsp.request_workspace_symbol(doc, symbol) + if not doc.lsp_open then return end + + for _, name in pairs(lsp.get_active_servers(doc.filename, true)) do + local server = lsp.servers_running[name] + if server.capabilities.workspaceSymbolProvider then + local rs = SymbolResults(symbol) + core.root_view:get_active_node_default():add_view(rs) + server:push_request('workspace/symbol', { + params = { + query = symbol, + -- TODO: implement status notifications but seems not supported + -- by tested lsp servers so far. + -- workDoneToken = "some-identifier", + -- partialResultToken = "some-other-identifier" + }, + callback = function(server, response) + if response.result and #response.result > 0 then + for index, result in ipairs(response.result) do + rs:add_result(result) + if index % 100 == 0 then + coroutine.yield() + rs.list:resize_to_parent() + end + end + rs.list:resize_to_parent() + end + rs:stop_searching() + end + }) + break + end + break + end +end + +--- Request a list of symbols for the given document for easy document +-- navigation and displays them using core.command_view:enter() +function lsp.request_document_symbols(doc) + if not doc.lsp_open then return end + + local servers_found = false + local symbols_retrieved = false + for _, name in pairs(lsp.get_active_servers(doc.filename, true)) do + servers_found = true + local server = lsp.servers_running[name] + if server.capabilities.documentSymbolProvider then + log(server, "Retrieving document symbols...") + server:push_request('textDocument/documentSymbol', { + params = { + textDocument = { + uri = util.touri(core.project_absolute_path(doc.filename)), + } + }, + callback = function(server, response) + if response.result and response.result and #response.result > 0 then + local symbols, symbol_names = get_symbol_lists(response.result) + core.command_view:enter("Find Symbol", { + submit = function(text, item) + if item then + local symbol = symbols[item.name] + -- The lsp may return a location object with range + -- and uri inside of it or just range as part of + -- the symbol it self. + symbol = symbol.location and symbol.location or symbol + if not symbol.uri then + local line1, col1 = util.toselection(symbol.range, doc) + doc:set_selection(line1, col1, line1, col1) + else + lsp.goto_location(symbol) + end + end + end, + suggest = function(text) + local res = common.fuzzy_match(symbol_names, text) + for i, name in ipairs(res) do + res[i] = { + text = util.split(name, "||")[1], + info = Server.get_symbol_kind(symbols[name].kind), + name = name + } + end + return res + end + }) + end + end + }) + symbols_retrieved = true + break + end + end + + if not servers_found then + core.log("[LSP] " .. "No server running") + elseif not symbols_retrieved then + core.log("[LSP] " .. "Document symbols not supported") + end +end + +--- Format current document if supported by one of the running lsp servers. +function lsp.request_document_format(doc) + if not doc.lsp_open then return end + + local servers_found = false + local format_executed = false + for _, name in pairs(lsp.get_active_servers(doc.filename, true)) do + servers_found = true + local server = lsp.servers_running[name] + if server.capabilities.documentFormattingProvider then + local trim_trailing_whitespace = false + local trim_newlines = false + if type(config.plugins.trimwhitespace) == "table" + and config.plugins.trimwhitespace.enabled + then + trim_trailing_whitespace = true + trim_newlines = config.plugins.trimwhitespace.trim_empty_end_lines + elseif config.plugins.trimwhitespace then -- Plugin enabled with true + trim_trailing_whitespace = true + trim_newlines = true + end + local indent_type, indent_size, indent_confirmed = doc:get_indent_info() + if not indent_confirmed then + indent_type, indent_size = config.tab_type, config.indent_size + end + server:push_request('textDocument/formatting', { + params = { + textDocument = { + uri = util.touri(core.project_absolute_path(doc.filename)), + }, + options = { + tabSize = indent_size, + insertSpaces = indent_type == "soft", + trimTrailingWhitespace = trim_trailing_whitespace, + insertFinalNewline = false, + trimFinalNewlines = trim_newlines + } + }, + callback = function(server, response) + if response.error and response.error.message then + log(server, "Error formatting: " .. response.error.message) + elseif response.result and #response.result > 0 then + -- Apply edits in reverse, as the ranges don't consider + -- the intermediate states. + -- Consider the TextEdits as already sorted. + -- If there are servers that don't sort their TextEdits, + -- we'll add sorting code. + for i=#response.result,1,-1 do + apply_edit(server, doc, response.result[i], false, false) + end + log(server, "Formatted document") + else + log(server, "Formatting not required") + end + end + }) + format_executed = true + break + end + end + + if not servers_found then + core.log("[LSP] " .. "No server running") + elseif not format_executed then + core.log("[LSP] " .. "Formatting not supported") + end +end + +function lsp.view_document_diagnostics(doc) + local diagnostic_messages = diagnostics.get(core.project_absolute_path(doc.filename)) + if not diagnostic_messages or #diagnostic_messages <= 0 then + core.log("[LSP] %s", "No diagnostic messages found.") + return + end + + local diagnostic_labels = { "Error", "Warning", "Info", "Hint" } + + local indexes, captions = {}, {} + for index, diagnostic in pairs(diagnostic_messages) do + local line1, col1 = util.toselection(diagnostic.range) + local label = diagnostic_labels[diagnostic.severity or diagnostics.severity.ERROR] + .. ": " .. diagnostic.message .. " " + .. tostring(line1) .. ":" .. tostring(col1) + captions[index] = label + indexes[label] = index + end + + core.command_view:enter("Filter Diagnostics", { + submit = function(text, item) + if item then + local diagnostic = diagnostic_messages[item.index] + local line1, col1 = util.toselection(diagnostic.range, doc) + doc:set_selection(line1, col1, line1, col1) + end + end, + suggest = function(text) + local res = common.fuzzy_match(captions, text) + for i, name in ipairs(res) do + local diagnostic = diagnostic_messages[indexes[name]] + local line1, col1 = util.toselection(diagnostic.range) + res[i] = { + text = diagnostics.lintplus_kinds[diagnostic.severity or diagnostics.severity.ERROR] + .. ": " .. diagnostic.message, + info = tostring(line1) .. ":" .. tostring(col1), + index = indexes[name] + } + end + return res + end + }) +end + +function lsp.view_all_diagnostics() + if diagnostics.count <= 0 then + core.log("[LSP] %s", "No diagnostic messages found.") + return + end + + local captions = {} + for _, diagnostic in ipairs(diagnostics.list) do + table.insert( + captions, + core.normalize_to_project_dir(diagnostic.filename) + ) + end + + core.command_view:enter("Filter Files", { + submit = function(text, item) + if item then + core.root_view:open_doc( + core.open_doc( + common.home_expand( + text + ) + ) + ) + end + end, + suggest = function(text) + local res = common.fuzzy_match(captions, text, true) + for i, name in ipairs(res) do + local diagnostics_count = diagnostics.get_messages_count( + core.project_absolute_path(name) + ) + res[i] = { + text = name, + info = "Messages: " .. diagnostics_count + } + end + return res + end + }) +end + +--- Jumps to the definition or implementation of the symbol where the cursor +-- is placed if the LSP server supports it +function lsp.goto_symbol(doc, line, col, implementation) + if not doc.lsp_open then return end + + for _, name in pairs(lsp.get_active_servers(doc.filename, true)) do + local server = lsp.servers_running[name] + + local method = "" + if not implementation then + if server.capabilities.definitionProvider then + method = method .. "definition" + elseif server.capabilities.declarationProvider then + method = method .. "declaration" + elseif server.capabilities.typeDefinitionProvider then + method = method .. "typeDefinition" + else + log(server, "Goto definition not supported") + return + end + else + if server.capabilities.implementationProvider then + method = method .. "implementation" + else + log(server, "Goto implementation not supported") + return + end + end + + -- Send document updates first + lsp.update_document(doc) + + server:push_request("textDocument/" .. method, { + params = get_buffer_position_params(doc, line, col), + callback = function(server, response) + local location = response.result + + if not location or not location.uri and #location == 0 then + core.log("[LSP] No %s found.", method) + return + end + + if not location.uri and #location > 1 then + listbox.clear() + for _, loc in pairs(location) do + local preview, position = get_location_preview(loc) + listbox.append { + text = preview, + info = position, + location = loc + } + end + listbox.show_list(nil, function(doc, item) + lsp.goto_location(item.location) + end) + else + if not location.uri then + location = location[1] + end + lsp.goto_location(location) + end + end + }) + end +end + +-- +-- Thread to process server requests and responses +-- without blocking entirely the editor. +-- +core.add_thread(function() + while true do + local servers_running = false + for _,server in pairs(lsp.servers_running) do + -- Send raw data to server which is usually big and slow in a + -- non blocking way by creating a coroutine just for it. + if #server.raw_list > 0 then + local raw_send = coroutine.create(function() + server:process_raw() + end) + coroutine.resume(raw_send) + while coroutine.status(raw_send) ~= "dead" do + -- while sending raw request we only read from lsp to not + -- conflict with the written raw data so remember no calls + -- here to: server:process_client_responses() + -- or server:process_notifications() + server:process_errors(config.plugins.lsp.log_server_stderr) + server:process_responses() + coroutine.yield() + coroutine.resume(raw_send) + end + end + + if not config.plugins.lsp.more_yielding then + server:process_notifications() + server:process_requests() + server:process_responses() + server:process_client_responses() + else + server:process_notifications() + coroutine.yield() + server:process_requests() + coroutine.yield() + server:process_responses() + server:process_client_responses() + coroutine.yield() + end + + server:process_errors(config.plugins.lsp.log_server_stderr) + + servers_running = true + end + + if servers_running then + local wait = 0.01 + if config.plugins.lsp.more_yielding then wait = 0 end + coroutine.yield(wait) + else + coroutine.yield(2) + end + end +end) + +-- +-- Events patching +-- +local doc_load = Doc.load +local doc_save = Doc.save +local doc_on_close = Doc.on_close +local doc_raw_insert = Doc.raw_insert +local doc_raw_remove = Doc.raw_remove +local root_view_on_text_input = RootView.on_text_input +local root_view_on_mouse_moved = RootView.on_mouse_moved + +function Doc:load(...) + local res = doc_load(self, ...) + -- skip new files + if self.filename and config.plugins.lsp.autostart_server then + diagnostics.lintplus_init_doc(self) + core.add_thread(function() + lsp.start_server(self.filename, core.project_dir) + lsp.open_document(self) + end) + end + return res +end + +function Doc:save(...) + local old_filename = self.filename + local res = doc_save(self, ...) + if old_filename ~= self.filename then + -- seems to be a new document so we send open notification + diagnostics.lintplus_init_doc(self) + core.add_thread(function() + lsp.open_document(self) + end) + else + core.add_thread(function() + lsp.update_document(self) + lsp.save_document(self) + end) + end + return res +end + +function Doc:on_close() + doc_on_close(self) + + -- skip new files + if not self.filename then return end + core.add_thread(function() + lsp.close_document(self) + end) + + if not config.plugins.lsp.stop_unneeded_servers then + return + end + + -- Check if any running lsp servers is not needed anymore and stop it + for name, server in pairs(lsp.servers_running) do + local doc_found = false + for _, docu in ipairs(core.docs) do + if docu.filename then + if common.match_pattern(docu.filename, server.file_patterns) then + doc_found = true + break + end + end + end + + if not doc_found and not server.exit_timer then + local t = Timer(server.quit_timeout * 1000, true) + t.on_timer = function() + server:exit() + core.log("[LSP] stopped %s", name) + lsp.servers_running = util.table_remove_key(lsp.servers_running, name) + end + t:start() + server.exit_timer = t + end + end +end + +local function add_change(self, text, line1, col1, line2, col2) + if not self.lsp_changes then + self.lsp_changes = {} + self.lsp_version = 0 + end + + local change = { range = {}, text = text} + change.range["start"] = {line = line1-1, character = col1-1} + change.range["end"] = {line = line2-1, character = col2-1} + + for _, name in pairs(lsp.get_active_servers(self.filename, true)) do + local server = lsp.servers_running[name] + if not self.lsp_changes[server] then + self.lsp_changes[server] = {} + end + table.insert(self.lsp_changes[server], change) + end + + -- TODO: this should not be needed but changing documents rapidly causes this + if type(self.lsp_version) ~= 'nil' then + self.lsp_version = self.lsp_version + 1 + else + self.lsp_version = 1 + end +end + +function Doc:raw_insert(line, col, text, undo_stack, time) + doc_raw_insert(self, line, col, text, undo_stack, time) + + -- skip new files + if not self.filename then return end + + col = util.doc_utf8_to_utf16(self, line, col) + + if self.lsp_open then + add_change(self, text, line, col, line, col) + lsp.update_document(self) + elseif #lsp.get_active_servers(self.filename, true) > 0 then + add_change(self, text, line, col, line, col) + end +end + +function Doc:raw_remove(line1, col1, line2, col2, undo_stack, time) + local lcol1 = util.doc_utf8_to_utf16(self, line1, col1) + local lcol2 = util.doc_utf8_to_utf16(self, line2, col2) + + doc_raw_remove(self, line1, col1, line2, col2, undo_stack, time) + + -- skip new files + if not self.filename then return end + + if self.lsp_open then + add_change(self, "", line1, lcol1, line2, lcol2) + lsp.update_document(self) + elseif #lsp.get_active_servers(self.filename, true) > 0 then + add_change(self, "", line1, lcol1, line2, lcol2) + end +end + +function RootView:on_text_input(text) + root_view_on_text_input(self, text) + + -- this part should actually trigger after Doc:raw_insert and Doc:raw_remove + -- so it is safe to trigger autocompletion from here. + local av = get_active_docview() + + if av then + lsp.user_typed = true + lsp.update_document(av.doc, true) + end +end + +function RootView:on_mouse_moved(x, y, dx, dy) + root_view_on_mouse_moved(self, x, y, dx, dy) + + if not config.plugins.lsp.mouse_hover then return end + + lsp.hover_position.x = x + lsp.hover_position.y = y + if lsp.hover_position.triggered then + local doc, line, col = lsp.get_hovered_location(x, y) + if doc == lsp.hover_position.doc and lsp.hover_position.utf8_range then + local utf8_range = lsp.hover_position.utf8_range + local line1, col1, line2, col2 = utf8_range.line1, utf8_range.col1, + utf8_range.line2, utf8_range.col2 + if (line > line1 or (line == line1 and col >= col1)) and + (line < line2 or (line == line2 and col <= col2)) then + return + end + end + listbox.hide() + lsp.hover_position.triggered = false + end + lsp.hover_timer:set_interval(config.plugins.lsp.mouse_hover_delay) + lsp.hover_timer:restart() +end + +-- +-- Add status view item to show document diagnostics count +-- +core.status_view:add_item({ + predicate = function() + local dv = get_active_docview() + if dv then + local filename = core.project_absolute_path(dv.doc.filename) + local diagnostic_messages = diagnostics.get(filename) + if diagnostic_messages and #diagnostic_messages > 0 then + return true + end + end + return false + end, + name = "lsp:diagnostics", + alignment = StatusView.Item.RIGHT, + get_item = function() + local dv = get_active_docview() + if dv then + local filename = core.project_absolute_path(dv.doc.filename) + local diagnostic_messages = diagnostics.get(filename) + + if diagnostic_messages and #diagnostic_messages > 0 then + return { + style.warn, + style.icon_font, "!", + style.font, " " .. tostring(#diagnostic_messages) + } + end + end + + return {} + end, + command = "lsp:view-document-diagnostics", + position = 1, + tooltip = "LSP Diagnostics", + separator = core.status_view.separator2 +}) + +-- +-- Register autocomplete icons +-- +if autocomplete.add_icon then + local autocomplete_icons = { + { name = "Text", color = "keyword", icon = '' }, -- U+F77E + { name = "Method", color = "function", icon = '' }, -- U+F6A6 + { name = "Function", color = "function", icon = '' }, -- U+F794 + { name = "Constructor", color = "literal", icon = '' }, -- U+F423 + { name = "Field", color = "keyword2", icon = 'ﰠ' }, -- U+FC20 + { name = "Variable", color = "keyword2", icon = '' }, -- U+F52A + { name = "Class", color = "literal", icon = 'ﴯ' }, -- U+FD2F + { name = "Interface", color = "literal", icon = '' }, -- U+F0E8 + { name = "Module", color = "literal", icon = '' }, -- U+F487 + { name = "Property", color = "keyword2", icon = 'ﰠ' }, -- U+FC20 + { name = "Unit", color = "number", icon = '塞' }, -- U+F96C + { name = "Value", color = "string", icon = '' }, -- U+F89F + { name = "Enum", color = "keyword2", icon = '' }, -- U+F15D + { name = "Keyword", color = "keyword", icon = '' }, -- U+F80A + { name = "Snippet", color = "keyword", icon = '' }, -- U+F44F + { name = "Color", color = "string", icon = '' }, -- U+F8D7 + { name = "File", color = "string", icon = '' }, -- U+F718 + { name = "Reference", color = "string", icon = '' }, -- U+F706 + { name = "Folder", color = "string", icon = '' }, -- U+F74A + { name = "EnumMember", color = "number", icon = '' }, -- U+F15D + { name = "Constant", color = "number", icon = '' }, -- U+F8FE + { name = "Struct", color = "keyword2", icon = 'פּ' }, -- U+FB44 + { name = "Event", color = "keyword", icon = '' }, -- U+F0E7 + { name = "Operator", color = "operator", icon = '' }, -- U+F694 + { name = "Unknown", color = "keyword", icon = '' }, -- U+F128 + { name = "TypeParameter", color = "literal", icon = '' } -- U+EA92 + } + + -- We add the font here to let it automatically scale by the scale plugin + style.syntax_fonts["lsp_symbols"] = renderer.font.load( + USERDIR .. "/plugins/lsp/fonts/symbols.ttf", + 15 * SCALE + ) + + for _, icon in ipairs(autocomplete_icons) do + autocomplete.add_icon( + icon.name, icon.icon, style.syntax_fonts["lsp_symbols"], icon.color + ) + end +end + +-- +-- Commands +-- +command.add( + function() + local dv = get_active_docview() + return dv ~= nil and dv.doc.lsp_open, dv and dv.doc or nil + end, { + + ["lsp:complete"] = function(doc) + local line1, col1, line2, col2 = doc:get_selection() + if line1 == line2 and col1 == col2 then + lsp.request_completion(doc, line1, col1, true) + end + end, + + ["lsp:goto-definition"] = function(doc) + local line1, col1, line2 = doc:get_selection() + if line1 == line2 then + lsp.goto_symbol(doc, line1, col1) + end + end, + + ["lsp:goto-implementation"] = function(doc) + local line1, col1, line2 = doc:get_selection() + if line1 == line2 then + lsp.goto_symbol(doc, line1, col1, true) + end + end, + + ["lsp:show-signature"] = function(doc) + local line1, col1, line2, col2 = doc:get_selection() + if line1 == line2 and col1 == col2 then + lsp.request_signature(doc, line1, col1, true) + end + end, + + ["lsp:show-symbol-info"] = function(doc) + local line1, col1, line2 = doc:get_selection() + if line1 == line2 then + lsp.request_hover(doc, line1, col1) + end + end, + + ["lsp:show-symbol-info-in-tab"] = function(doc) + local line1, col1, line2 = doc:get_selection() + if line1 == line2 then + lsp.request_hover(doc, line1, col1, true) + end + end, + + ["lsp:view-call-hierarchy"] = function(doc) + local line1, col1, line2 = doc:get_selection() + if line1 == line2 then + lsp.request_call_hierarchy(doc, line1, col1) + end + end, + + ["lsp:view-document-symbols"] = function(doc) + lsp.request_document_symbols(doc) + end, + + ["lsp:format-document"] = function(doc) + lsp.request_document_format(doc) + end, + + ["lsp:view-document-diagnostics"] = function(doc) + lsp.view_document_diagnostics(doc) + end, + + ["lsp:rename-symbol"] = function(doc) + local symbol = doc:get_text(doc:get_selection()) + local line1, col1, line2 = doc:get_selection() + if #symbol > 0 and line1 == line2 then + core.command_view:enter("New Symbol Name", { + text = symbol, + submit = function(new_name) + lsp.request_symbol_rename(doc, line1, col1, new_name) + end + }) + else + core.log("Please select a symbol on the document to rename.") + end + end, + + ["lsp:find-references"] = function(doc) + local line1, col1, line2 = doc:get_selection() + if line1 == line2 then + lsp.request_references(doc, line1, col1) + end + end +}) + +command.add(nil, { + ["lsp:view-all-diagnostics"] = function() + lsp.view_all_diagnostics() + end, + + ["lsp:find-workspace-symbol"] = function() + local dv = get_active_docview() + local doc = dv and dv.doc or nil + local symbol = doc and doc:get_text(doc:get_selection()) or "" + core.command_view:enter("Find Workspace Symbol", { + text = symbol, + submit = function(query) + lsp.request_workspace_symbol(doc, query) + end + }) + end, + + ["lsp:toggle-diagnostics"] = function() + if not diagnostics.lintplus_found then + core.error("[LSP] Please install lintplus for diagnostics rendering.") + return + end + lsp.toggle_diagnostics() + end, + + ["lsp:stop-servers"] = function() + lsp.stop_servers() + end, + + ["lsp:start-servers"] = function() + lsp.start_servers() + end, + + ["lsp:restart-servers"] = function() + lsp.stop_servers() + lsp.start_servers() + end +}) + +-- +-- Default Keybindings +-- +keymap.add { + ["ctrl+space"] = "lsp:complete", + ["ctrl+shift+space"] = "lsp:show-signature", + ["alt+a"] = "lsp:show-symbol-info", + ["alt+shift+a"] = "lsp:show-symbol-info-in-tab", + ["alt+d"] = "lsp:goto-definition", + ["alt+shift+d"] = "lsp:goto-implementation", + ["alt+s"] = "lsp:view-document-symbols", + ["alt+shift+s"] = "lsp:find-workspace-symbol", + ["alt+f"] = "lsp:find-references", + ["alt+shift+f"] = "lsp:format-document", + ["alt+e"] = "lsp:view-document-diagnostics", + ["ctrl+alt+e"] = "lsp:view-all-diagnostics", + ["alt+shift+e"] = "lsp:toggle-diagnostics", + ["alt+c"] = "lsp:view-call-hierarchy", + ["alt+r"] = "lsp:rename-symbol", +} + +-- +-- Register context menu items +-- +local function lsp_predicate(_, _, also_in_symbol) + local dv = get_active_docview() + if dv then + local doc = dv.doc + + if #lsp.get_active_servers(doc.filename, true) < 1 then + return false + elseif not also_in_symbol then + return true + end + + -- Make sure the cursor is place near a document symbol (word) + local linem, colm = doc:get_selection() + local linel, coll = doc:position_offset(linem, colm, translate.start_of_word) + local liner, colr = doc:position_offset(linem, colm, translate.end_of_word) + + local word_left = doc:get_text(linel, coll, linem, colm) + local word_right = doc:get_text(linem, colm, liner, colr) + + if #word_left > 0 or #word_right > 0 then + return true + end + end + return false +end + +local function lsp_predicate_symbols() + return lsp_predicate(nil, nil, true) +end + +local menu_found, menu = pcall(require, "plugins.contextmenu") +if menu_found then + menu:register(lsp_predicate_symbols, { + menu.DIVIDER, + { text = "Show Symbol Info", command = "lsp:show-symbol-info" }, + { text = "Show Symbol Info in Tab", command = "lsp:show-symbol-info-in-tab" }, + { text = "Goto Definition", command = "lsp:goto-definition" }, + { text = "Goto Implementation", command = "lsp:goto-implementation" }, + { text = "Find References", command = "lsp:find-references" } + }) + + menu:register(lsp_predicate, { + menu.DIVIDER, + { text = "Document Symbols", command = "lsp:view-document-symbols" }, + { text = "Document Diagnostics", command = "lsp:view-document-diagnostics" }, + { text = "Toggle Diagnostics", command = "lsp:toggle-diagnostics" }, + { text = "Format Document", command = "lsp:format-document" }, + }) + + local menu_show = menu.show + function menu:show(...) + lsp.hover_timer:stop() + lsp.hover_timer:reset() + listbox.hide() + lsp.hover_position.triggered = false + menu_show(self, ...) + end +end + + +return lsp + diff --git a/debian/extra/plugins/lsp/json.lua b/debian/extra/plugins/lsp/json.lua new file mode 100644 index 0000000..eb36b8f --- /dev/null +++ b/debian/extra/plugins/lsp/json.lua @@ -0,0 +1,532 @@ +-- +-- json.lua +-- Origin: https://github.com/rxi/json.lua +-- +-- Copyright (c) 2020 rxi +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +-- of the Software, and to permit persons to whom the Software is furnished to do +-- so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all +-- copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. +-- + +local json = { _version = "0.1.2" } + +local error_message = "" + +-- Lets us explicitly add null values to table elements +json.null = "{{json::null}}" + +-- Treat numbers longer than 14 digits as a string by adding this to the +-- beginning of the string for encoder to recognize. This prevents any data +-- loss due to lua 5.2 not supporting big integer numbers and converting big +-- integers to floats. The drawback is that the user should manually convert +-- these strings to a number. Numbers with less than 15 digits are not affected. +json.number_flag = "{{json::num}}" +local number_flag_len = #json.number_flag + +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- + +local encode + +local escape_char_map = { + [ "\\" ] = "\\", + [ "\"" ] = "\"", + [ "\b" ] = "b", + [ "\f" ] = "f", + [ "\n" ] = "n", + [ "\r" ] = "r", + [ "\t" ] = "t", +} + +local escape_char_map_inv = { [ "/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end + + +local function escape_char(c) + return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) +end + + +local function encode_nil(val) + return "null" +end + + +local function encode_table(val, stack) + local res = {} + stack = stack or {} + + -- Circular reference? + if stack[val] then error("circular reference") end + + stack[val] = true + + if rawget(val, 1) ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + if n ~= #val then + error("invalid table: sparse array") + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + if #res > 0 then + return "[" .. table.concat(res, ",") .. "]" + else + return "{}" + end + + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end + + +local function encode_string(val) + if val == json.null then + return "null" + elseif + #val > number_flag_len + and + string.sub(val, 1, number_flag_len) == json.number_flag + then + local num = string.sub(val, number_flag_len+1) + return num + end + return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' +end + + +local function encode_number(val) + -- Check for NaN, -inf and inf + if val ~= val or val <= -math.huge or val >= math.huge then + error("unexpected number value '" .. tostring(val) .. "'") + end + return string.format("%.14g", val) +end + + +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} + + +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end + + +function json.encode(val, prettify) + local out = ( encode(val) ) + if prettify then + return json.prettify(out) + end + return out +end + + +------------------------------------------------------------------------------- +-- Decode +------------------------------------------------------------------------------- + +local parse + +local function create_set(...) + local res = {} + for i = 1, select("#", ...) do + res[ select(i, ...) ] = true + end + return res +end + +local space_chars = create_set(" ", "\t", "\r", "\n") +local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") +local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") +local literals = create_set("true", "false", "null") + +local literal_map = { + [ "true" ] = true, + [ "false" ] = false, + [ "null" ] = nil, +} + +local function decode_error(str, idx, msg) + local line_count = 1 + local col_count = 1 + for i = 1, idx - 1 do + col_count = col_count + 1 + if str:sub(i, i) == "\n" then + line_count = line_count + 1 + col_count = 1 + end + end + error_message = string.format("%s at line %d col %d", msg, line_count, col_count) +end + + +local function next_char(str, idx, set, negate) + if type(idx) ~= "number" then + decode_error(str, #str, "invalid json string") + return #str + 1 + end + for i = idx, #str do + if set[str:sub(i, i)] ~= negate then + return i + end + end + return #str + 1 +end + + +local function codepoint_to_utf8(n) + -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa + local f = math.floor + if n <= 0x7f then + return string.char(n) + elseif n <= 0x7ff then + return string.char(f(n / 64) + 192, n % 64 + 128) + elseif n <= 0xffff then + return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) + elseif n <= 0x10ffff then + return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, + f(n % 4096 / 64) + 128, n % 64 + 128) + end + error( string.format("invalid unicode codepoint '%x'", n) ) +end + + +local function parse_unicode_escape(s) + local n1 = tonumber( s:sub(1, 4), 16 ) + local n2 = tonumber( s:sub(7, 10), 16 ) + -- Surrogate pair? + if n2 then + return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) + else + return codepoint_to_utf8(n1) + end +end + + +local function parse_string(str, i) + local res = "" + local j = i + 1 + local k = j + + while j <= #str do + local x = str:byte(j) + + if x < 32 then + decode_error(str, j, "control character in string") + + elseif x == 92 then -- `\`: Escape + res = res .. str:sub(k, j - 1) + j = j + 1 + local c = str:sub(j, j) + if c == "u" then + local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) + or str:match("^%x%x%x%x", j + 1) + or decode_error(str, j - 1, "invalid unicode escape in string") + res = res .. parse_unicode_escape(hex) + j = j + #hex + else + if not escape_chars[c] then + decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") + end + res = res .. escape_char_map_inv[c] + end + k = j + 1 + + elseif x == 34 then -- `"`: End of string + res = res .. str:sub(k, j - 1) + return res, j + 1 + end + + j = j + 1 + end + + decode_error(str, i, "expected closing quote for string") +end + + +local function parse_number(str, i) + local x = next_char(str, i, delim_chars) + local s = str:sub(i, x - 1) + local n = nil + if #s > 14 then + n = json.number_flag .. s + else + n = tonumber(s) + end + if not n then + decode_error(str, i, "invalid number '" .. s .. "'") + end + return n, x +end + + +local function parse_literal(str, i) + local x = next_char(str, i, delim_chars) + local word = str:sub(i, x - 1) + if not literals[word] then + decode_error(str, i, "invalid literal '" .. word .. "'") + end + return literal_map[word], x +end + + +local function parse_array(str, i) + local res = {} + local n = 1 + i = i + 1 + while 1 do + local x + i = next_char(str, i, space_chars, true) + -- Empty / end of array? + if str:sub(i, i) == "]" then + i = i + 1 + break + end + -- Read token + x, i = parse(str, i) + res[n] = x + n = n + 1 + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "]" then break end + if chr ~= "," then decode_error(str, i, "expected ']' or ','") end + end + return res, i +end + + +local function parse_object(str, i) + local res = {} + i = i + 1 + while 1 do + local key, val + i = next_char(str, i, space_chars, true) + -- Empty / end of object? + if str:sub(i, i) == "}" then + i = i + 1 + break + end + -- Read key + if str:sub(i, i) ~= '"' then + decode_error(str, i, "expected string for key") + end + key, i = parse(str, i) + -- Read ':' delimiter + i = next_char(str, i, space_chars, true) + if str:sub(i, i) ~= ":" then + decode_error(str, i, "expected ':' after key") + end + i = next_char(str, i + 1, space_chars, true) + -- Read value + val, i = parse(str, i) + -- Set + res[key] = val + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "}" then break end + if chr ~= "," then decode_error(str, i, "expected '}' or ','") end + end + return res, i +end + + +local char_func_map = { + [ '"' ] = parse_string, + [ "0" ] = parse_number, + [ "1" ] = parse_number, + [ "2" ] = parse_number, + [ "3" ] = parse_number, + [ "4" ] = parse_number, + [ "5" ] = parse_number, + [ "6" ] = parse_number, + [ "7" ] = parse_number, + [ "8" ] = parse_number, + [ "9" ] = parse_number, + [ "-" ] = parse_number, + [ "t" ] = parse_literal, + [ "f" ] = parse_literal, + [ "n" ] = parse_literal, + [ "[" ] = parse_array, + [ "{" ] = parse_object, +} + + +parse = function(str, idx) + local chr = str:sub(idx, idx) + local f = char_func_map[chr] + if f then + return f(str, idx) + end + decode_error(str, idx, "unexpected character '" .. chr .. "'") +end + +function json.last_error() + return error_message +end + +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + error_message = "" + local res, idx = parse(str, next_char(str, 1, space_chars, true)) + idx = next_char(str, idx, space_chars, true) + if idx <= #str then + decode_error(str, idx, "trailing garbage") + end + if error_message ~= "" then + return false + end + return res +end + +local function indent(code, level, indent_width) + return string.rep(" ", level * indent_width) .. code +end + +--- Implemented some json prettifier but not a parser so +--- don't expect it to give you parsing errors :D +--- @param text string The json string +--- @param indent_width? integer The amount of spaces per indentation +--- @return string +function json.prettify(text, indent_width) + if type(text) ~= "string" then + return "" + end + + local out = "" + indent_width = indent_width or 2 + + local indent_level = 0 + local reading_literal = false + local previous_was_escape = false + local inside_string = false + local in_value = false + local last_was_bracket = false + local string_char = "" + local last_char = "" + + for char in text:gmatch(".") do + if (char == "{" or char == "[") and not inside_string then + if not in_value or last_was_bracket then + out = out .. indent(char, indent_level, indent_width) .. "\n" + else + out = out .. char .. "\n" + end + last_was_bracket = true + in_value = false + indent_level = indent_level + 1 + elseif (char == '"' or char == "'") and not inside_string then + inside_string = true + string_char = char + if not in_value then + out = out .. indent(char, indent_level, indent_width) + else + out = out .. char + end + elseif inside_string then + local pe_set = false + if char == "\\" and previous_was_escape then + previous_was_escape = false + elseif char == "\\" then + previous_was_escape = true + pe_set = true + end + out = out .. char + if char == string_char and not previous_was_escape then + inside_string = false + elseif previous_was_escape and not pe_set then + previous_was_escape = false + end + elseif char == ":" then + in_value = true + last_was_bracket = false + out = out .. char .. " " + elseif char == "," then + in_value = false + reading_literal = false + out = out .. char .. "\n" + elseif char == "}" or char == "]" then + indent_level = indent_level - 1 + if + (char == "}" and last_char == "{") + or + (char == "]" and last_char == "[") + then + out = out:gsub("%s*\n$", "") .. char + else + out = out .. "\n" .. indent(char, indent_level, indent_width) + end + elseif not char:match("%s") and not reading_literal then + reading_literal = true + if not in_value or last_was_bracket then + out = out .. indent(char, indent_level, indent_width) + last_was_bracket = false + else + out = out .. char + end + elseif not char:match("%s") then + out = out .. char + end + + if not char:match("%s") then + last_char = char + end + end + + return out +end + + +return json diff --git a/debian/extra/plugins/lsp/listbox.lua b/debian/extra/plugins/lsp/listbox.lua new file mode 100644 index 0000000..33284b0 --- /dev/null +++ b/debian/extra/plugins/lsp/listbox.lua @@ -0,0 +1,580 @@ +-- A configurable listbox that can be used as tooltip, selection box and +-- selection box with fuzzy search, this may change in the future. +-- +-- @note This code is a readaptation of autocomplete plugin from rxi :) +-- +-- TODO implement select box with fuzzy search + +local core = require "core" +local common = require "core.common" +local command = require "core.command" +local style = require "core.style" +local keymap = require "core.keymap" +local util = require "plugins.lsp.util" +local RootView = require "core.rootview" +local DocView = require "core.docview" + +---@class lsp.listbox.item +---@field text string +---@field info string +---@field on_draw fun(item:lsp.listbox.item, x:number, y:number, calc_only?:boolean):number + +---@alias lsp.listbox.callback fun(doc: core.doc, item: lsp.listbox.item) + +---@class lsp.listbox.signature_param +---@field label string + +---@class lsp.listbox.signature +---@field label string +---@field activeParameter? integer +---@field activeSignature? integer +---@field parameters lsp.listbox.signature_param[] + +---@class lsp.listbox.signature_list +---@field activeParameter? integer +---@field activeSignature? integer +---@field signatures lsp.listbox.signature[] + +---@class lsp.listbox.position +---@field line integer +---@field col integer + +---@class lsp.listbox +local listbox = {} + +---@class lsp.listbox.settings +---@field items lsp.listbox.item[] +---@field shown_items lsp.listbox.item[] +---@field selected_item_idx integer +---@field show_items_count boolean +---@field max_height integer +---@field active_view core.docview | nil +---@field line integer | nil +---@field col integer | nil +---@field last_line integer | nil +---@field last_col integer | nil +---@field callback lsp.listbox.callback | nil +---@field is_list boolean +---@field has_fuzzy_search boolean +---@field above_text boolean +local settings = { + items = {}, + shown_items = {}, + selected_item_idx = 1, + show_items_count = false, + max_height = 6, + active_view = nil, + line = nil, + col = nil, + last_line = nil, + last_col = nil, + callback = nil, + is_list = false, + has_fuzzy_search = false, + above_text = false, +} + +local mt = { __tostring = function(t) return t.text end } + +-------------------------------------------------------------------------------- +-- Private functions +-------------------------------------------------------------------------------- + +---@return core.docview | nil +local function get_active_view() + if getmetatable(core.active_view) == DocView then + return core.active_view + end +end + +---@param active_view core.docview +---@return number x +---@return number y +---@return number width +---@return number height +local function get_suggestions_rect(active_view) + if #settings.shown_items == 0 then + listbox.hide() + return 0, 0, 0, 0 + end + + local line, col + if settings.line then + line, col = settings.line, settings.col + else + line, col = active_view.doc:get_selection() + end + + -- Validate line against current view because there can be cases + -- when user rapidly switches between tabs causing the deferred draw + -- to be called late and the current document view already changed. + if line > #active_view.doc.lines then + listbox.hide() + return 0, 0, 0, 0 + end + + local x, y = active_view:get_line_screen_position(line) + + -- This function causes tokenizer to fail if given line is greater than + -- the amount of lines the document holds, so validation above is needed. + x = x + active_view:get_col_x_offset(line, col) + + local padding_x = style.padding.x + local padding_y = style.padding.y + + if settings.above_text and line > 1 then + y = y - active_view:get_line_height() - style.padding.y + else + y = y + active_view:get_line_height() + style.padding.y + end + + local font = settings.is_list and active_view:get_font() or style.font + local text_height = font:get_height() + + local max_width = 0 + for _, item in ipairs(settings.shown_items) do + local w = 0 + if item.on_draw then + w = item.on_draw(item, 0, 0, true) + else + w = font:get_width(item.text) + if item.info then + w = w + style.font:get_width(item.info) + style.padding.x + end + end + max_width = math.max(max_width, w) + end + + local max_items = #settings.shown_items + if settings.is_list and max_items > settings.max_height then + max_items = settings.max_height + end + + -- additional line to display total items + if settings.show_items_count then + max_items = max_items + 1 + end + + if max_width < 150 then + max_width = 150 + end + + local height = max_items * (text_height + (padding_y/4)) + (padding_y*2) + local width = max_width + padding_x * 2 + + x = x - padding_x + y = y - padding_y + + local win_w = core.root_view.size.x + if (width/win_w*100) >= 85 and (width+style.padding.x*4) < win_w then + x = win_w - width - style.padding.x*2 + elseif width > (win_w - x) then + x = x - (width - (win_w - x)) + if x < 0 then + x = 0 + end + end + + return x, y, width, height +end + +---@param av core.docview +local function draw_listbox(av) + if #settings.shown_items <= 0 then + return + end + + -- draw background rect + local rx, ry, rw, rh = get_suggestions_rect(av) + + -- draw border + if not settings.is_list then + local border_width = 1 + renderer.draw_rect( + rx - border_width, + ry - border_width, + rw + (border_width * 2), + rh + (border_width * 2), + style.divider + ) + end + + renderer.draw_rect(rx, ry, rw, rh, style.background3) + + local padding_x = style.padding.x + local padding_y = style.padding.y + + -- draw text + local font = settings.is_list and av:get_font() or style.font + local line_height = font:get_height() + (padding_y / 4) + local y = ry + padding_y + + local max_height = settings.max_height + + local show_count = ( + #settings.shown_items <= max_height or not settings.is_list + ) and + #settings.shown_items or max_height + + local start_index = settings.selected_item_idx > max_height and + (settings.selected_item_idx-(max_height-1)) or 1 + + for i=start_index, start_index+show_count-1, 1 do + if not settings.shown_items[i] then + break + end + + local item = settings.shown_items[i] + + if item.on_draw then + item.on_draw(item, rx + padding_x, y) + else + local color = (i == settings.selected_item_idx and settings.is_list) and + style.accent or style.text + + common.draw_text( + font, color, item.text, "left", + rx + padding_x, y, rw, line_height + ) + + if item.info then + color = (i == settings.selected_item_idx and settings.is_list) and + style.text or style.dim + + common.draw_text( + style.font, color, item.info, "right", + rx, y, rw - padding_x, line_height + ) + end + end + y = y + line_height + end + + if settings.show_items_count then + renderer.draw_rect(rx, y, rw, 2, style.caret) + renderer.draw_rect(rx, y+2, rw, line_height, style.background) + common.draw_text( + style.font, + style.accent, + "Items", + "left", + rx + padding_x, y, rw, line_height + ) + common.draw_text( + style.font, + style.accent, + tostring(settings.selected_item_idx) .. "/" .. tostring(#settings.shown_items), + "right", + rx, y, rw - padding_x, line_height + ) + end +end + +---Set the document position where the listbox will be draw. +---@param position? lsp.listbox.position +local function set_position(position) + if type(position) == "table" then + settings.line = position.line + settings.col = position.col + else + settings.line = nil + settings.col = nil + end +end + +-------------------------------------------------------------------------------- +-- Public functions +-------------------------------------------------------------------------------- + +---@param elements lsp.listbox.item[] +function listbox.add(elements) + if type(elements) == "table" and #elements > 0 then + local items = {} + for _, element in pairs(elements) do + table.insert(items, setmetatable(element, mt)) + end + settings.items = items + end +end + +function listbox.clear() + settings.items = {} + settings.selected_item_idx = 1 + settings.shown_items = {} + settings.line = nil + settings.col = nil +end + +---@param element lsp.listbox.item +function listbox.append(element) + table.insert(settings.items, setmetatable(element, mt)) +end + +function listbox.hide() + settings.active_view = nil + settings.line = nil + settings.col = nil + settings.selected_item_idx = 1 + settings.shown_items = {} + core.redraw = true +end + +---@param is_list? boolean +---@param position? lsp.listbox.position +function listbox.show(is_list, position) + set_position(position) + + local active_view = get_active_view() + if active_view then + settings.active_view = active_view + settings.last_line, settings.last_col = active_view.doc:get_selection() + if settings.items and #settings.items > 0 then + settings.is_list = is_list or false + settings.shown_items = settings.items + end + end + core.redraw = true +end + +---@param text string +---@param position? lsp.listbox.position +function listbox.show_text(text, position) + if text and type("text") == "string" then + local win_w = core.root_view.size.x - style.padding.x * 6 + text = util.wrap_text(text, style.font, win_w) + + local items = {} + for result in string.gmatch(text.."\n", "(.-)\n") do + table.insert(items, {text = result}) + end + listbox.add(items) + end + + listbox.show(false, position) +end + +---@param items lsp.listbox.item[] +---@param callback lsp.listbox.callback +---@param position? lsp.listbox.position +function listbox.show_list(items, callback, position) + listbox.add(items) + + if callback then + settings.callback = callback + end + + listbox.show(true, position) +end + +---@param signatures lsp.listbox.signature_list +---@param position? lsp.listbox.position +function listbox.show_signatures(signatures, position) + local active_parameter = nil + local active_signature = nil + + if signatures.activeParameter then + active_parameter = signatures.activeParameter + 1 + end + + if signatures.activeSignature then + active_signature = signatures.activeSignature + 1 + end + + local signatures_count = #signatures.signatures + + local items = {} + for index, signature in ipairs(signatures.signatures) do + table.insert(items, { + text = signature.label, + signature = signature, + on_draw = function(item, x, y, calc_only) + local width = 0 + local height = style.font:get_height() + + if item.signature.parameters then + if signatures_count > 1 then + if index == active_signature then + width = style.font:get_width("> ") + else + width = style.font:get_width("> ") + x = x + style.font:get_width("> ") + end + end + + width = width + + style.font:get_width("(") + + style.font:get_width(")") + + if not calc_only then + if signatures_count > 1 and index == active_signature then + x = renderer.draw_text(style.font, "> ", x, y, style.caret) + end + x = renderer.draw_text(style.font, "(", x, y, style.text) + end + + local params_count = #item.signature.parameters + for pindex, param in ipairs(item.signature.parameters) do + local label = "" + if type(param.label) == "table" then + label = signature.label:sub(param.label[1]+1, param.label[2]) + else + label = param.label + end + if label and pindex ~= params_count then + label = label .. ", " + end + width = width + style.font:get_width(label) + if not calc_only then + local color = style.text + if + ( + signature.activeParameter + and + (signature.activeParameter + 1) == pindex + ) + or + (index == active_signature and active_parameter == pindex) + then + color = style.accent + end + x = renderer.draw_text( + style.font, + label, + x, y, + color + ) + end + end + + if not calc_only then + renderer.draw_text(style.font, ")", x, y, style.text) + end + else + width = style.font:get_width(item.signature.label) + if not calc_only then + renderer.draw_text( + style.font, + item.signature.label, + x, y, + style.text + ) + end + end + return width, width > 0 and height or 0 + end + }) + end + + listbox.add(items) + + listbox.show(false, position) +end + +function listbox.toggle_above(enable) + if enable then + settings.above_text = true + else + settings.above_text = false + end +end + +-------------------------------------------------------------------------------- +-- Patch event logic into RootView +-------------------------------------------------------------------------------- +local root_view_update = RootView.update +local root_view_draw = RootView.draw + +RootView.update = function(...) + root_view_update(...) + + if not settings.active_view then return end + + local active_view = get_active_view() + if active_view then + -- reset suggestions if caret was moved or not same active view + local line, col = active_view.doc:get_selection() + if + settings.active_view ~= active_view + or + line ~= settings.last_line or col ~= settings.last_col + then + listbox.hide() + end + else + listbox.hide() + end +end + +RootView.draw = function(...) + if settings.active_view then + local active_view = get_active_view() + if + active_view and settings.active_view == active_view + and + #settings.shown_items > 0 + then + -- draw suggestions box after everything else + core.root_view:defer_draw(draw_listbox, active_view) + end + end + root_view_draw(...) +end + +-------------------------------------------------------------------------------- +-- Commands +-------------------------------------------------------------------------------- +local function predicate() + local av = get_active_view() + return av and settings.active_view and #settings.shown_items > 0, av +end + +command.add(predicate, { + ["listbox:select"] = function(av) + ---@cast av core.docview + if settings.is_list then + local doc = av.doc + local item = settings.shown_items[settings.selected_item_idx] + + if settings.callback then + settings.callback(doc, item) + end + + listbox.hide() + end + end, + + ["listbox:previous"] = function() + if settings.is_list then + settings.selected_item_idx = math.max(settings.selected_item_idx - 1, 1) + else + listbox.hide() + end + end, + + ["listbox:next"] = function() + if settings.is_list then + settings.selected_item_idx = math.min( + settings.selected_item_idx + 1, #settings.shown_items + ) + else + listbox.hide() + end + end, + + ["listbox:cancel"] = function() + listbox.hide() + end, +}) + +-------------------------------------------------------------------------------- +-- Keymaps +-------------------------------------------------------------------------------- +keymap.add { + ["tab"] = "listbox:select", + ["up"] = "listbox:previous", + ["down"] = "listbox:next", + ["escape"] = "listbox:cancel", +} + + +return listbox diff --git a/debian/extra/plugins/lsp/manifest.json b/debian/extra/plugins/lsp/manifest.json new file mode 100644 index 0000000..0d37eec --- /dev/null +++ b/debian/extra/plugins/lsp/manifest.json @@ -0,0 +1,19 @@ +{ + "addons": [ + { + "id": "lsp", + "name": "Language Server Protocol", + "description": "Provides intellisense by leveraging the LSP protocol.", + "version": "0.10", + "mod_version": "3", + "dependencies": { + "widget": { "version": ">=0.1" }, + "lintplus": { "version": ">=0.2", "optional": true }, + "lsp_snippets": { "optional": true } + }, + "tags": [ + "language server protocol" + ] + } + ] +} diff --git a/debian/extra/plugins/lsp/server.lua b/debian/extra/plugins/lsp/server.lua new file mode 100644 index 0000000..33c8cca --- /dev/null +++ b/debian/extra/plugins/lsp/server.lua @@ -0,0 +1,1662 @@ +-- Class in charge of establishing communication with an LSP server and +-- managing requests, notifications and responses from both the server +-- and the client that is establishing the connection. +-- +-- @copyright Jefferson Gonzalez +-- @license MIT +-- @inspiration: https://github.com/orbitalquark/textadept-lsp +-- +-- LSP Documentation: +-- https://microsoft.github.io/language-server-protocol/specifications/specification-3-17 + +local json = require "plugins.lsp.json" +local util = require "plugins.lsp.util" +local diagnostics = require "plugins.lsp.diagnostics" +local Object = require "core.object" + +---@alias lsp.server.callback fun(server: lsp.server, ...) +---@alias lsp.server.timeoutcb fun(server: lsp.server, ...) +---@alias lsp.server.notificationcb fun(server: lsp.server, params: table) +---@alias lsp.server.responsecb fun(server: lsp.server, response: table, request?: lsp.server.request) + +---@class lsp.server.languagematch +---@field id string +---@field pattern string + +---@class lsp.server.request +---@field id integer +---@field method string +---@field data table|nil +---@field params table +---@field callback lsp.server.responsecb | nil +---@field overwritten boolean +---@field overwritten_callback lsp.server.responsecb | nil +---@field sending boolean +---@field raw_data string +---@field timeout number +---@field timeout_callback lsp.server.timeoutcb | nil +---@field timestamp number +---@field times_sent integer + +---LSP Server communication library. +---@class lsp.server : core.object +---@field public name string +---@field public language string | lsp.server.languagematch[] +---@field public file_patterns table +---@field public current_request integer +---@field public init_options table +---@field public settings table | nil +---@field public event_listeners table +---@field public message_listeners table +---@field public request_listeners table +---@field public request_list lsp.server.request[] +---@field public response_list table +---@field public notification_list lsp.server.request[] +---@field public raw_list lsp.server.request[] +---@field public command table +---@field public write_fails integer +---@field public write_fails_before_shutdown integer +---@field public verbose boolean +---@field public initialized boolean +---@field public hitrate_list table +---@field public requests_per_second integer +---@field public proc process | nil +---@field public quit_timeout number +---@field public exit_timer lsp.timer | nil +---@field public capabilities table +---@field public custom_capabilities table +---@field public yield_on_reads boolean +---@field public running boolean +local Server = Object:extend() + +---LSP Server constructor options +---@class lsp.server.options +---@field name string +---@field language string | lsp.server.languagematch[] +---@field file_patterns table +---@field string|command table +---@field quit_timeout number +---@field windows_skip_cmd boolean +---@field env table +---@field settings table +---@field init_options table +---@field custom_capabilities table +---@field on_start? fun(server: lsp.server) +---@field requests_per_second number +---@field incremental_changes boolean +Server.options = { + ---Name of the server + name = "", + ---Programming language identifier. + ---Can be a string or a table. + ---If the table is empty, the file extension will be used instead. + ---The table should be an array of tables containing `id` and `pattern`. + ---The `pattern` will be matched with the file path. + ---Will use the `id` of the first `pattern` that matches. + ---If no pattern matches, the file extension will be used instead. + language = {}, + ---Patterns to match the language files + file_patterns = {}, + ---Command to launch LSP server and optional arguments + command = {}, + ---On Windows, avoid running the LSP server with cmd.exe + windows_skip_cmd = false, + ---Enviroment variables to set for the server command + env = {}, + ---Seconds before closing the server when not needed anymore + quit_timeout = 60, + ---Optional table of settings to pass into the LSP + ---Note that also having a settings.json or settings.lua in + ---your workspace directory is supported + settings = {}, + ---Optional table of initializationOptions for the LSP + init_options = {}, + ---Optional table of capabilities that will be merged with our default one + custom_capabilities = {}, + ---Function called when the server has been started + on_start = nil, + ---Set by default to 16 should only be modified if having issues with a server + requests_per_second = 32, + ---Some servers like bash language server support incremental changes + ---which are more performant but don't advertise it, set to true to force + ---incremental changes even if server doesn't advertise them + incremental_changes = false, + ---True to debug the lsp client when developing it + verbose = false, +} + +---Default timeout when sending a request to lsp server. +---@type integer Time in seconds +Server.DEFAULT_TIMEOUT = 10 + +---The maximum amount of data to retrieve when reading from server. +---@type integer Amount of bytes +Server.BUFFER_SIZE = 1024 * 10 + +---LSP Docs: /#errorCodes +Server.error_code = { + ParseError = -32700, + InvalidRequest = -32600, + MethodNotFound = -32601, + InvalidParams = -32602, + InternalError = -32603, + jsonrpcReservedErrorRangeStart = -32099, + serverErrorStart = -32099, + ServerNotInitialized = -32002, + UnknownErrorCode = -32001, + jsonrpcReservedErrorRangeEnd = -32000, + serverErrorEnd = -32000, + lspReservedErrorRangeStart = -32899, + ContentModified = -32801, + RequestCancelled = -32800, + lspReservedErrorRangeEnd = -32800, +} + +---LSP Docs: /#completionTriggerKind +Server.completion_trigger_Kind = { + Invoked = 1, + TriggerCharacter = 2, + TriggerForIncompleteCompletions = 3 +} + +---LSP Docs: /#diagnosticSeverity +Server.diagnostic_severity = { + Error = 1, + Warning = 2, + Information = 3, + Hint = 4 +} + +---LSP Docs: /#textDocumentSyncKind +Server.text_document_sync_kind = { + None = 0, + Full = 1, + Incremental = 2 +} + +---LSP Docs: /#completionItemKind +Server.completion_item_kind = { + 'Text', 'Method', 'Function', 'Constructor', 'Field', 'Variable', 'Class', + 'Interface', 'Module', 'Property', 'Unit', 'Value', 'Enum', 'Keyword', + 'Snippet', 'Color', 'File', 'Reference', 'Folder', 'EnumMember', + 'Constant', 'Struct', 'Event', 'Operator', 'TypeParameter' +} + +---LSP Docs: /#symbolKind +Server.symbol_kind = { + 'File', 'Module', 'Namespace', 'Package', 'Class', 'Method', 'Property', + 'Field', 'Constructor', 'Enum', 'Interface', 'Function', 'Variable', + 'Constant', 'String', 'Number', 'Boolean', 'Array', 'Object', 'Key', + 'Null', 'EnumMember', 'Struct', 'Event', 'Operator', 'TypeParameter' +} + +---LSP Docs: /#insertTextFormat +Server.insert_text_format = { + PlainText = 1, + Snippet = 2 +} + +---LSP Docs: /#messageType +---@enum +Server.message_type = { + Error = 1, + Warning = 2, + Info = 3, + Log = 4, + Debug = 5 +} + +---LSP Docs: /#positionEncodingKind +---@enum +Server.position_encoding_kind = { + UTF8 = 'utf-8', + UTF16 = 'utf-16', + UTF32 = 'utf-32' +} + +---@class lsp.server.requestoptions +---@field params? table +---@field data? table @Optional data appended to request. +---@field callback? lsp.server.responsecb @Default callback executed when a response is received. +---@field overwrite? boolean @Substitute same previous request with new one if not sent. +---@field overwritten_callback? lsp.server.responsecb @Executed in place of original response callback if the request should have been overwritten but was already sent. +---@field raw_data? string @Request body used when sending a raw request. +---@field timeout? number @Timeout in seconds to consider the request unanswered. +---@field timeout_callback? lsp.server.timeoutcb @Callback executed when the request times out. + +---Get a completion kind label from its id or empty string if not found. +---@param id integer +---@return string +function Server.get_completion_item_kind(id) + return Server.completion_item_kind[id] or "" +end + +---Get list of completion kinds. +---@return table +function Server.get_completion_items_kind_list() + local list = {} + for i = 1, #Server.completion_item_kind do + if i ~= 15 then --Disable snippets + table.insert(list, i) + end + end + + return list +end + +---Get a symbol kind label from its id or empty string if not found. +---@param id integer +---@return string +function Server.get_symbol_kind(id) + return Server.symbol_kind[id] or "" +end + +---Get list of symbol kinds. +---@return table +function Server.get_symbols_kind_list() + local list = {} + for i = 1, #Server.symbol_kind do + list[i] = i + end + + return list +end + +---Given a ServerCapabilities object, return a "normalized" version +---that simplifies capabilities checks. +---@param capabilities table +---returns table +function Server.normalize_server_capabilities(capabilities) + local cap = util.deep_merge({ }, capabilities) + local tds = { + openClose = false, + change = false, + willSave = false, + willSaveWaitUntil = false, + save = false + } + if cap.textDocumentSync then + if type(cap.textDocumentSync) ~= "table" then + -- Convert TextDocumentSyncKind into TextDocumentSyncOptions + tds = util.deep_merge(tds, { + openClose = true, + change = cap.textDocumentSync, + save = { + includeText = false + } + }) + cap.textDocumentSync = nil + else + tds = util.deep_merge(tds, cap.textDocumentSync) + if type(tds.save) ~= "table" and tds.save then + tds.save = { + includeText = false + } + end + end + end + cap.textDocumentSync = util.deep_merge(cap.textDocumentSync, tds) + return cap +end + +---Instantiates a new LSP server. +---@param options lsp.server.options +function Server:new(options) + Server.super.new(self) + + self.name = options.name + self.language = options.language + self.file_patterns = options.file_patterns + self.current_request = 0 + self.init_options = options.init_options or {} + self.settings = options.settings or nil + self.event_listeners = {} + self.message_listeners = {} + self.request_listeners = {} + self.request_list = {} + self.response_list = {} + self.notification_list = {} + self.raw_list = {} + self.command = options.command + self.write_fails = 0 + self.fatal_error = false + self.snippets = options.snippets + self.fake_snippets = options.fake_snippets or false + -- TODO: We may need to lower this but tests so far show that some servers + -- may actually fail to write many of the request sent to it if it is + -- indexing the workspace source code or other heavy tasks. + self.write_fails_before_shutdown = 60 + self.verbose = options.verbose or false + self.last_restart = system.get_time() + self.initialized = false + self.hitrate_list = {} + self.requests_per_second = options.requests_per_second or 16 + + self.proc = process.start( + options.command, { + stderr = process.REDIRECT_PIPE, + env = options.env + } + ) + self.quit_timeout = options.quit_timeout or 60 + self.exit_timer = nil + self.capabilities = nil + self.custom_capabilities = options.custom_capabilities + self.yield_on_reads = false + self.incremental_changes = options.incremental_changes or false + + self.read_responses_coroutine = nil + + if options.on_start then options.on_start(self) end +end + +---Starts the LSP server process, any listeners should be registered before +---calling this method and this method should be called before any pushes. +---@param workspace string +---@param editor_name? string +---@param editor_version? string +function Server:initialize(workspace, editor_name, editor_version) + local root_uri = util.touri(workspace); + + self.path = workspace or "" + self.editor_name = editor_name or "unknown" + self.editor_version = editor_version or "0.1" + + self:push_request('initialize', { + timeout = 10, + params = { + processId = system["get_process_id"] and system.get_process_id() or nil, + clientInfo = { + name = editor_name or "unknown", + version = editor_version or "0.1" + }, + -- TODO: locale + rootPath = workspace, + rootUri = root_uri, + workspaceFolders = { + {uri = root_uri, name = util.getpathname(workspace)} + }, + initializationOptions = self.init_options, + capabilities = util.deep_merge({ + workspace = { + configuration = true -- 'workspace/configuration' requests + }, + textDocument = { + synchronization = { + -- willSave = true, + -- willSaveWaitUntil = true, + didSave = true, + -- dynamicRegistration = false -- not supported + }, + completion = { + -- dynamicRegistration = false, -- not supported + completionItem = { + -- Snippets are required by css-languageserver + snippetSupport = self.snippets or self.fake_snippets, + -- commitCharactersSupport = true, + documentationFormat = {'plaintext'}, + -- deprecatedSupport = false, -- simple autocompletion list + -- preselectSupport = true + -- tagSupport = {valueSet = {}}, + insertReplaceSupport = true, + resolveSupport = {properties = {'documentation', 'detail', 'additionalTextEdits'}}, + -- insertTextModeSupport = {valueSet = {}} + }, + completionItemKind = { + valueSet = Server.get_completion_items_kind_list() + } + -- contextSupport = true + }, + hover = { + -- dynamicRegistration = false, -- not supported + contentFormat = {'markdown', 'plaintext'} + }, + signatureHelp = { + -- dynamicRegistration = false, -- not supported + signatureInformation = { + documentationFormat = {'plaintext'} + -- parameterInformation = {labelOffsetSupport = true}, + -- activeParameterSupport = true + } + -- contextSupport = true + }, + -- references = {dynamicRegistration = false}, -- not supported + -- documentHighlight = {dynamicRegistration = false}, -- not supported + documentSymbol = { + -- dynamicRegistration = false, -- not supported + symbolKind = {valueSet = Server.get_symbols_kind_list()} + -- hierarchicalDocumentSymbolSupport = true, + -- tagSupport = {valueSet = {}}, + -- labelSupport = true + }, + -- diagnostic = { + -- dynamicRegistration = true, + -- relatedDocumentSupport = false + -- }, + -- formatting = {dynamicRegistration = false},-- not supported + -- rangeFormatting = {dynamicRegistration = false}, -- not supported + -- onTypeFormatting = {dynamicRegistration = false}, -- not supported + -- declaration = { + -- dynamicRegistration = false, -- not supported + -- linkSupport = true + -- } + -- definition = { + -- dynamicRegistration = false, -- not supported + -- linkSupport = true + -- }, + -- typeDefinition = { + -- dynamicRegistration = false, -- not supported + -- linkSupport = true + -- }, + -- implementation = { + -- dynamicRegistration = false, -- not supported + -- linkSupport = true + -- }, + -- codeAction = { + -- dynamicRegistration = false, -- not supported + -- codeActionLiteralSupport = {valueSet = {}}, + -- isPreferredSupport = true, + -- disabledSupport = true, + -- dataSupport = true, + -- resolveSupport = {properties = {}}, + -- honorsChangeAnnotations = true + -- }, + -- codeLens = {dynamicRegistration = false}, -- not supported + -- documentLink = { + -- dynamicRegistration = false, -- not supported + -- tooltipSupport = true + -- }, + -- colorProvider = {dynamicRegistration = false}, -- not supported + -- rename = { + -- dynamicRegistration = false, -- not supported + -- prepareSupport = false + -- }, + publishDiagnostics = { + relatedInformation = true, + tagSupport = { + valueSet = { + diagnostics.tag.UNNECESSARY, + diagnostics.tag.DEPRECATED + } + }, + versionSupport = true, + codeDescriptionSupport = true, + dataSupport = false + }, + -- foldingRange = { + -- dynamicRegistration = false, -- not supported + -- rangeLimit = ?, + -- lineFoldingOnly = true + -- }, + -- selectionRange = {dynamicRegistration = false}, -- not supported + -- linkedEditingRange = {dynamicRegistration = false}, -- not supported + -- callHierarchy = {dynamicRegistration = false}, -- not supported + -- semanticTokens = { + -- dynamicRegistration = false, -- not supported + -- requests = {}, + -- tokenTypes = {}, + -- tokenModifiers = {}, + -- formats = {}, + -- overlappingTokenSupport = true, + -- multilineTokenSupport = true + -- }, + -- moniker = {dynamicRegistration = false} -- not supported + }, + window = { + -- workDoneProgress = true, + -- showMessage = {}, + showDocument = { support = true } + }, + general = { + -- regularExpressions = {}, + -- markdown = {}, + positionEncodings = { + Server.position_encoding_kind.UTF16 + } + }, + -- experimental = nil + }, self.custom_capabilities) + }, + callback = function(server, response) + if server.verbose then + server:log( + "Processing initialization response:\n%s", + util.jsonprettify(json.encode(response)) + ) + end + local result = response.result + if result then + server.capabilities = Server.normalize_server_capabilities(result.capabilities) + server.info = result.serverInfo + + if server.info then + server:log( + 'Connected to %s %s', + server.info.name, + server.info.version or '(unknown version)' + ) + end + + while not server:notify('initialized') do end -- required by protocol + + -- We wait a few seconds to prevent initialization issues + coroutine.yield(3) + server.initialized = true; + server:send_event_signal("initialized", server, result) + end + end + }) +end + +---Register an event listener. +---@param event_name string +---@param callback lsp.server.callback +function Server:add_event_listener(event_name, callback) + if self.verbose then + self:log( + "Listening for event '%s'", + event_name + ) + end + + if not self.event_listeners[event_name] then + self.event_listeners[event_name] = {} + end + table.insert(self.event_listeners[event_name], callback) +end + +function Server:send_event_signal(event_name, ...) + if self.event_listeners[event_name] then + for _, l in ipairs(self.event_listeners[event_name]) do + l(self, ...) + end + else + self:on_event(event_name) + end +end + +function Server:on_event(event_name) + if self.verbose then + self:log("Received event '%s'", event_name) + end +end + +---Send a message to the server that doesn't needs a response. +---@param method string +---@param params? table +---@return boolean sent +function Server:notify(method, params) + local message = { + jsonrpc = '2.0', + method = method, + params = params or {} + } + + local data = json.encode(message) + + if self.verbose then + self:log("Sending notification:\n%s", util.jsonprettify(data)) + end + + local sent, errmsg = self:write_request(data) + + if not sent and self.verbose then + self:log( + "Could not send '%s' notification with error: %s", + method, + errmsg or "unknown" + ) + end + + return sent +end + +---Reply to a server request. +---@param id integer +---@param result table +---@return boolean sent +function Server:respond(id, result) + local message = { + jsonrpc = '2.0', + id = id, + result = result + } + + local data = json.encode(message) + + if self.verbose then + self:log("Responding to '%d':\n%s", id, util.jsonprettify(data)) + end + + local sent, errmsg = self:write_request(data) + + if not sent and self.verbose then + self:log("Could not send response with error: %s", errmsg or "unknown") + end + + return sent +end + +---Respond to a an unknown server request with a method not found error code. +---@param id integer +---@param error_message? string +---@param error_code? integer +---@return boolean sent +function Server:respond_error(id, error_message, error_code) + local message = { + jsonrpc = '2.0', + id = id, + error = { + code = error_code or Server.error_code.MethodNotFound, + message = error_message or "method not found" + } + } + + local data = json.encode(message) + + if self.verbose then + self:log("Responding error to '%d':\n%s", id, util.jsonprettify(data)) + end + + local sent, errmsg = self:write_request(data) + + if not sent and self.verbose then + self:log("Could not send response with error: %s", errmsg or "unknown") + end + + return sent +end + +---Sends one of the queued notifications. +function Server:process_notifications() + if not self.initialized then return end + + -- Clone table as we remove elements while iterating it + local notifications = {} + for index, request in ipairs(self.notification_list) do + notifications[index] = request + end + + for index, request in ipairs(notifications) do + request.sending = true + local message = { + jsonrpc = '2.0', + method = request.method, + params = request.params or {} + } + + local data = json.encode(message) + + if self.verbose then + self:log( + "Sending notification '%s':\n%s", + request.method, + util.jsonprettify(data) + ) + end + + local written, errmsg = self:write_request(data) + + if self.verbose then + if not written then + self:log( + "Failed sending notification '%s' with error: %s", + request.method, + errmsg or "unknown" + ) + end + end + + if written then + if request.callback then + request.callback(self) + end + table.remove(self.notification_list, index) + self.write_fails = 0 + return request + else + self:shutdown_if_needed() + return + end + end +end + +---Sends one of the queued client requests. +function Server:process_requests() + if not self.proc then return end + + local remove_request = nil + for index, request in ipairs(self.request_list) do + if request.timestamp < os.time() then + -- only process when initialized or the initialize request + -- which should be the first one. + if not self.initialized and request.id ~= 1 then + return nil + end + + local message = { + jsonrpc = '2.0', + id = request.id, + method = request.method, + params = request.params or {} + } + + local data = json.encode(message) + + local written, errmsg = self:write_request(data) + + if self.verbose then + if written then + self:log( + "Sent request '%s':\n%s", + request.method, + util.jsonprettify(data) + ) + else + self:log( + "Failed sending request '%s' with error: %s\n%s", + request.method, + errmsg or "unknown", + util.jsonprettify(data) + ) + end + end + + if written then + local time = request.timeout or 1 + request.timestamp = os.time() + time + + self.write_fails = 0 + + -- if request has been sent more than 2 times remove them + request.times_sent = request.times_sent + 1 + if + request.times_sent > 1 + and + request.id ~= 1 -- Initialize request may take some time + then + remove_request = index + break + else + return request + end + else + request.timestamp = os.time() + 1 + self:shutdown_if_needed() + return nil + end + end + end + + if remove_request then + local request = table.remove(self.request_list, remove_request) + if self.verbose then + self:log("Request '%s' expired without response", remove_request) + end + if request.timeout_callback then + request.timeout_callback(request) + end + end + + return nil +end + +---Read the lsp server stdout, parse any responses, requests or +---notifications and properly dispatch signals to any listeners. +function Server:process_responses() + if not self.proc then return end + + local responses = self:read_responses(0) + + if type(responses) == "table" then + for _, response in pairs(responses) do + if self.verbose then + self:log( + "Processing Response:\n%s", + util.jsonprettify(json.encode(response)) + ) + end + if not response.id then + -- A notification, event or generic message was received + self:send_message_signal(response) + elseif + response.result + or + (not response.params and not response.method) + then + -- An actual request response was received + self:send_response_signal(response) + else + -- The server is making a request + self:send_request_signal(response) + end + end + end + + return responses +end + +---Sends all queued client responses to server. +function Server:process_client_responses() + if not self.initialized then return end + + ::send_responses:: + for index, response in ipairs(self.response_list) do + local message = { + jsonrpc = '2.0', + id = response.id + } + + if response.result then + message.result = response.result + else + message.error = response.error + end + + local data = json.encode(message) + + if self.verbose then + self:log("Sending client response:\n%s", util.jsonprettify(data)) + end + + local written, errmsg = self:write_request(data) + + if self.verbose then + if not written then + self:log( + "Failed sending client response '%s' with error: %s", + response.id, + errmsg or "unknown" + ) + end + end + + if written then + self.write_fails = 0 + table.remove(self.response_list, index) + -- restart loop after removing from table to prevent issues + goto send_responses + else + self:shutdown_if_needed() + return + end + end +end + +---Should be called periodically to prevent the server from stalling +---because of not flushing the stderr (especially true of clangd). +---@param log_errors boolean +function Server:process_errors(log_errors) + if not self.proc then return end + + local errors = self:read_errors(0) + + if #errors > 0 and log_errors then + self:log("Error: \n'%s'", errors) + end + + return errors +end + +---Sends raw data to the server process and ensures that all of it is written +---if no errors occur, otherwise it returns false and the error message. Notice +---that this function can perform yielding when ran inside of a coroutine. +---@param data string +---@return boolean sent +---@return string? errmsg +function Server:send_data(data) + local proc = self.proc -- save current process to avoid it changing + if not proc then return false end + + local failures, data_len = 0, #data + local written, errmsg = proc:write(data) + local total_written = written or 0 + + while total_written < data_len and not errmsg do + written, errmsg = proc:write(data:sub(total_written + 1)) + total_written = total_written + (written or 0) + + if (not written or written <= 0) and not errmsg and coroutine.running() then + -- with each consecutive fail the yield timeout is increased by 5ms + coroutine.yield((failures * 5) / 1000) + + failures = failures + 1 + if failures > 19 then -- after ~1000ms we error out + errmsg = "maximum amount of consecutive failures reached" + break + end + else + failures = 0 + end + end + + if errmsg then + self:log("Error sending data: '%s'\n%s", errmsg, data) + end + + return total_written == data_len, errmsg +end + +---Send one of the queued chunks of raw data to lsp server which are +---usually huge, like the textDocument/didOpen notification. +function Server:process_raw() + if not self.initialized then return end + + -- Wait until everything else is processed to prevent initialization issues + if + #self.notification_list > 0 + or + #self.request_list > 0 + or + #self.response_list > 0 + then + return + end + + if not self.proc or not self.proc:running() then + self.raw_list = {} + return + end + + local sent = false + for index, raw in ipairs(self.raw_list) do + raw.sending = true + + -- first send the header + if + not self:send_data(string.format( + 'Content-Length: %d\r\n\r\n', #raw.raw_data + )) + then + break + end + + if self.verbose then + self:log("Raw header written") + end + + -- send content in chunks + local chunks = 10 * 1024 + raw.raw_data = raw.raw_data + + while #raw.raw_data > 0 do + if not self.proc or not self.proc:running() then + self.raw_list = {} + return + end + + if #raw.raw_data > chunks then + -- TODO: perform proper error handling + self:send_data(raw.raw_data:sub(1, chunks)) + raw.raw_data = raw.raw_data:sub(chunks+1) + else + -- TODO: perform proper error handling + self:send_data(raw.raw_data) + raw.raw_data = "" + end + + self.write_fails = 0 + + coroutine.yield() + end + + if self.verbose then + self:log("Raw content written") + end + + if raw.callback then + raw.callback(self, raw) + end + + table.remove(self.raw_list, index) + sent = true + break + end + if sent then collectgarbage("collect") end +end + +---Help controls the amount of requests sent to the lsp server per second +---which prevents overloading it and causing a pipe hang. +---@param type string +---@return boolean true if max hitrate was reached +function Server:hitrate_reached(type) + if not self.hitrate_list[type] then + self.hitrate_list[type] = { + count = 1, + timestamp = os.time() + 1 + } + elseif self.hitrate_list[type].timestamp > os.time() then + if self.hitrate_list[type].count >= self.requests_per_second then + return true + end + self.hitrate_list[type].count = self.hitrate_list[type].count + 1 + else + self.hitrate_list[type].timestamp = os.time() + 1 + self.hitrate_list[type].count = 1 + end + return false +end + +---Check if it is possible to queue a new request of any kind except +---raw ones. This is useful to delay a request and not loose it in case +---the lsp reached maximum amount of hit rate per second. +function Server:can_push() + local type = "request" + if not self.hitrate_list[type] then + return self.initialized + elseif self.hitrate_list[type].timestamp > os.time() then + if self.hitrate_list[type].count >= self.requests_per_second then + return false + end + end + return self.initialized +end + +-- Notifications that should bypass the hitrate limit +local notifications_whitelist = { + "textDocument/didOpen", + "textDocument/didSave", + "textDocument/didClose" +} + +---Queue a new notification but ignores new ones if the hit rate was reached. +---@param method string +---@param options lsp.server.requestoptions +function Server:push_notification(method, options) + assert(options.params, "please provide the parameters for the notification") + + if options.overwrite then + for _, notification in ipairs(self.notification_list) do + if notification.method == method and not notification.sending then + if self.verbose then + self:log("Overwriting notification %s", tostring(method)) + end + notification.params = options.params + notification.callback = options.callback + notification.data = options.data + return + end + end + end + + if + method ~= "textDocument/didOpen" + and + self:hitrate_reached("request") + and + not util.intable(method, notifications_whitelist) + then + return + end + + if self.verbose then + self:log( + "Pushing notification '%s':\n%s", + method, + util.jsonprettify(json.encode(options.params)) + ) + end + + -- Store the notification for later processing on responses_loop + table.insert(self.notification_list, { + method = method, + params = options.params, + callback = options.callback, + data = options.data, + }) +end + +-- Requests that should bypass the hitrate limit +local requests_whitelist = { + "completionItem/resolve" +} + +---Queue a new request but ignores new ones if the hit rate was reached. +---@param method string +---@param options lsp.server.requestoptions +function Server:push_request(method, options) + if not self.initialized and method ~= "initialize" then + return + end + + assert(options.params, "please provide the parameters for the request") + + if options.overwrite then + for _, request in ipairs(self.request_list) do + if request.method == method then + if request.times_sent > 0 then + request.overwritten = true + break + else + request.params = options.params + request.callback = options.callback + request.overwritten_callback = options.overwritten_callback + request.data = options.data + request.timeout = options.timeout + request.timeout_callback = options.timeout_callback + request.timestamp = 0 + if self.verbose then + self:log("Overwriting request %s", tostring(method)) + end + return + end + end + end + end + + if + method ~= "initialize" + and + self:hitrate_reached("request") + and + not util.intable(method, requests_whitelist) + then + return + end + + if self.verbose then + self:log("Adding request %s", tostring(method)) + end + + -- Set the request id + self.current_request = self.current_request + 1 + + -- Store the request for later processing on responses_loop + table.insert(self.request_list, { + id = self.current_request, + method = method, + params = options.params, + callback = options.callback, + overwritten_callback = options.overwritten_callback, + data = options.data, + timeout = options.timeout, + timeout_callback = options.timeout_callback, + timestamp = 0, + times_sent = 0 + }) +end + +---Queue a client response to a server request which can be an error +---or a regular response, one of both. This may ignore new ones if +---the hit rate was reached. +---@param method string +---@param id integer +---@param result table|nil +---@param error table|nil +function Server:push_response(method, id, result, error) + if self:hitrate_reached("request") then + return + end + + if self.verbose then + self:log("Adding response %s to %s", tostring(id), tostring(method)) + end + + -- Store the response for later processing on loop + local response = { + id = id + } + if result then + response.result = result + else + response.error = error + end + + table.insert(self.response_list, response) +end + +---Send raw json strings to server in cases where the json encoder +---would be too slow to convert a lua table into a json representation. +---@param name string A name to identify the request when overwriting. +---@param options lsp.server.requestoptions +function Server:push_raw(name, options) + assert(options.raw_data, "please provide the raw_data for request") + + if options.overwrite then + for _, request in ipairs(self.raw_list) do + if request.method == name then + if not request.sending then + request.raw_data = options.raw_data + request.callback = options.callback + request.data = options.data + if self.verbose then + self:log("Overwriting raw request %s", tostring(name)) + end + return + end + break + end + end + end + + if self.verbose then + self:log("Adding raw request %s", name) + end + + -- Store the request for later processing on responses_loop + table.insert(self.raw_list, { + method = name, + raw_data = options.raw_data, + callback = options.callback, + data = options.data, + }) +end + +---Retrieve a request and removes it from the internal requests list +---@param id integer +---@return lsp.server.request | nil +function Server:pop_request(id) + for index, request in ipairs(self.request_list) do + if request.id == id then + table.remove(self.request_list, index) + return request + end + end + return nil +end + +---Try to fetch a server responses, notifications or requests +---in a specific amount of time. +---@param timeout integer Time in seconds, set to 0 to not wait +---@return table[]|boolean Responses list or false if failed +function Server:read_responses(timeout) + local proc = self.proc -- save current process to avoid it changing + if not proc or not proc:running() then + return false + end + + if not self.read_responses_coroutine then + self.read_responses_coroutine = coroutine.create(function() + local buffer = "" + while true do + -- Read out all the headers + local output = buffer .. (proc:read_stdout(Server.BUFFER_SIZE) or "") + local content_start = output:match("\r\n\r\n()") + local buf = output + while not content_start do + if #output > 1024 then + -- After a kilobyte, still no end in sight for headers. Error out. + return error(string.format("Can't find headers delimiter after %d bytes. ".. + "Something wrong with the server configuration?\nGot:\n%s", #output, output)) + end + coroutine.yield(#buf > 0) + buf = proc:read_stdout(Server.BUFFER_SIZE) + if not buf then + -- If we stopped in the middle of a read, error out + if #output > 0 then + return error(string.format("Can't continue reading stdout:\n%s", output)) + end + return + end + if #buf > 0 then + output = output .. buf + content_start = output:match("\r\n\r\n()") + end + end + + -- Parse headers + local headers_data = output:sub(1, content_start - 4 - 1) + local content_length = 0 + local headers = util.split(headers_data, "\r\n") + for _, header in ipairs(headers) do + -- We only care for Content-Length for now + local length = header:match("^Content%-Length: (%d+)$") + if length then + content_length = tonumber(length) + break + end + end + if not content_length then + return error(string.format("Bad header content:\n%s\n", headers_data)) + end + + -- Read all the expected content data + local content_data_t = { output:sub(content_start) } + buf = content_data_t[1] + local content_read_length = #buf + while content_read_length < content_length do + coroutine.yield(#buf > 0) + buf = proc:read_stdout(Server.BUFFER_SIZE) + if not buf then + return error(string.format("Can't continue reading stdout. Stopped at %d/%d.\n%s", + content_read_length, content_length, table.concat(content_data_t))) + end + content_read_length = content_read_length + #buf + table.insert(content_data_t, buf) + end + local content_data = table.concat(content_data_t) + -- We only need content_length bytes, so queue the rest for the next loop + buffer = content_data:sub(content_length + 1) + content_data = content_data:sub(1, content_length) + + if self.verbose then + self:log("Got data.\nHeaders:\n%s\n\nContent:\n%s", headers_data, content_data) + end + + coroutine.yield(#buffer > 0, content_data) + end + end) + end + + if coroutine.status(self.read_responses_coroutine) == "dead" then + self.fatal_error = true + self:shutdown_if_needed() + return false + end + + timeout = timeout or Server.DEFAULT_TIMEOUT + local max_time = timeout == 0 and math.huge or system.get_time() + timeout + + local responses = {} + repeat + local status, has_more_data, response = coroutine.resume(self.read_responses_coroutine) + if response then table.insert(responses, response) end + if not status then + local error_msg = has_more_data + self:log("Disconnecting from server:\n%s", error_msg) + self.fatal_error = true + self:shutdown_if_needed() + return false + end + until not has_more_data or (timeout > 0 and system.get_time() >= max_time) + + if #responses > 0 then + for index, data in ipairs(responses) do + local json_data = json.decode(data) + if json_data ~= false then + responses[index] = json_data + else + responses[index] = nil + self:log( + "JSON Parser Error: %s\n%s\n%s", + json.last_error(), + "-----", + data + ) + return false + end + end + + if #responses > 0 then + -- Reset write fails since server is sending responses + self.write_fails = 0 + + return responses + end + elseif self.verbose and timeout > 0 then + self:log("Could not read a response in %d seconds", timeout) + end + + return false +end + +---Get messages thrown by the stderr pipe of the server. +---@param timeout integer Time in seconds, set to 0 to not wait +---@return string|nil +function Server:read_errors(timeout) + local proc = self.proc -- save current process to avoid it changing + if not proc then return "" end + + timeout = timeout or Server.DEFAULT_TIMEOUT + local inside_coroutine = self.yield_on_reads and coroutine.running() or false + + local max_time = os.time() + timeout + if timeout == 0 then max_time = max_time + 1 end + local output = "" + while max_time > os.time() and output == "" do + output = proc:read_stderr(Server.BUFFER_SIZE) + if timeout == 0 then break end + if output == "" and inside_coroutine then + coroutine.yield() + end + end + + if timeout == 0 and output ~= "" then + local new_output = nil + while new_output ~= "" do + new_output = proc:read_stderr(Server.BUFFER_SIZE) + if new_output ~= "" then + if new_output == nil then + break + end + output = output .. new_output + if inside_coroutine then + coroutine.yield() + end + end + end + end + + return output or "" +end + +---Try to send a request to a server in a specific amount of time. +---@param data table | string Table or string with the json request +---@return boolean written +---@return string? errmsg +function Server:write_request(data) + if not self.proc or not self.proc:running() then + return false + end + + if type(data) == "table" then + data = json.encode(data) + end + + -- WARNING: send_data performs yielding which can pontentially cause a + -- race condition, in case of future issues this may be the root cause. + return self:send_data(string.format( + 'Content-Length: %d\r\n\r\n%s', + #data, + data + )) +end + +function Server:log(message, ...) + print (string.format("%s: " .. message .. "\n", self.name, ...)) +end + +---Call an apropriate signal handler for a given response. +---@param response table +function Server:send_response_signal(response) + local request = self:pop_request(response.id) + if request then + if not request.overwritten and request.callback then + request.callback(self, response, request) + elseif request.overwritten and request.overwritten_callback then + request.overwritten_callback(self, response, request) + end + return + end + self:on_response(response, request) +end + +---Called for each response that doesn't has a signal handler. +---@param response table +---@param request lsp.server.request | nil +function Server:on_response(response, request) + if self.verbose then + self:log( + "Received response '%s' with result:\n%s", + response.id, + util.jsonprettify(json.encode(response)) + ) + end +end + +---Register a request handler. +---@param method string +---@param callback lsp.server.responsecb +function Server:add_request_listener(method, callback) + if self.verbose then + self:log( + "Registering listener for '%s' requests", + method + ) + end + + if not self.request_listeners[method] then + self.request_listeners[method] = {} + end + table.insert(self.request_listeners[method], callback) +end + +---Call an apropriate signal handler for a given request. +---@param request table +function Server:send_request_signal(request) + if not request.method then + if self.verbose and request.id then + self:log( + "Received empty response for previous request '%s'", + request.id + ) + end + return + end + + if self.request_listeners[request.method] then + for _, l in ipairs(self.request_listeners[request.method]) do + l(self, request) + end + else + self:on_request(request) + end +end + +---Called for each request that doesn't has a signal handler. +---@param request table +function Server:on_request(request) + if self.verbose then + self:log( + "Received request '%s' with data:\n%s", + request.method, + util.jsonprettify(json.encode(request)) + ) + end + + self:push_response( + request.method, + request.id, + nil, + { + code = Server.error_code.MethodNotFound, + message = "Method not found" + } + ) +end + +---Register a specialized message or notification listener. +---Notice that if no specialized listener is registered the +---on_notification() method will be called instead. +---@param method string +---@param callback lsp.server.notificationcb +function Server:add_message_listener(method, callback) + if self.verbose then + self:log( + "Registering listener for '%s' messages", + method + ) + end + + if not self.message_listeners[method] then + self.message_listeners[method] = {} + end + table.insert(self.message_listeners[method], callback) +end + +---Call an apropriate signal handler for a given message or notification. +---@param message table +function Server:send_message_signal(message) + if self.message_listeners[message.method] then + for _, l in ipairs(self.message_listeners[message.method]) do + l(self, message.params) + end + else + self:on_message(message.method, message.params) + end +end + +---Called for every message or notification without a signal handler. +---@param method string +---@Param params table +function Server:on_message(method, params) + if self.verbose then + self:log( + "Received notification '%s' with params:\n%s", + method, + util.jsonprettify(json.encode(params)) + ) + end +end + +---Return the languageId for the specified doc. +---@param doc core.doc +---@return string +function Server:get_language_id(doc) + if type(self.language) == "string" then + return self.language + else + for _, l in ipairs(self.language) do + if string.match(doc.abs_filename, l.pattern) then + return l.id + end + end + end + return util.file_extension(doc.filename) +end + +---Kills the server process and deinitialize the server object state. +function Server:stop() + self.initialized = false + self.proc = nil + + self.request_list = {} + self.response_list = {} + self.notification_list = {} + self.raw_list = {} +end + +---Shutdown the server if not running or amount of write fails +---reached the maximum allowed. +function Server:shutdown_if_needed() + if + self.write_fails >= self.write_fails_before_shutdown + or + (self.proc and not self.proc:running()) + or + self.fatal_error + then + self:stop() + self:on_shutdown() + return + end + self.write_fails = self.write_fails + 1 +end + +---Can be overwritten to handle server shutdowns. +function Server:on_shutdown() + self:log("The server was shutdown.") +end + +---Sends a shutdown notification to lsp and then stop it. +function Server:exit() + self.initialized = false + + -- Send shutdown request + local message = { + jsonrpc = '2.0', + id = self.current_request + 1, + method = "shutdown", + params = {} + } + + self:write_request(json.encode(message)) + + -- send exit notification + self:notify('exit') + + self:stop() +end + + +return Server diff --git a/debian/extra/plugins/lsp/symbolresults.lua b/debian/extra/plugins/lsp/symbolresults.lua new file mode 100644 index 0000000..96c39cd --- /dev/null +++ b/debian/extra/plugins/lsp/symbolresults.lua @@ -0,0 +1,121 @@ +-- +-- SymbolResults Widget/View. +-- @copyright Jefferson Gonzalez +-- @license MIT +-- + +local style = require "core.style" +local Widget = require "libraries.widget" +local Label = require "libraries.widget.label" +local Line = require "libraries.widget.line" +local ListBox = require "libraries.widget.listbox" +local Server = require "plugins.lsp.server" + +local Lsp = {} + +---@class lsp.symbolresults : widget +---@field public searching boolean +---@field public symbol string +---@field private title widget.label +---@field private line widget.line +---@field private list_container widget +---@field private list widget.listbox +local SymbolResults = Widget:extend() + +function SymbolResults:new(symbol) + SymbolResults.super.new(self) + + Lsp = require "plugins.lsp" + + self.name = "Symbols Search" + self.defer_draw = false + + self.searching = true + self.symbol = symbol or "" + self.title = Label(self, "Searching symbols for: " .. symbol) + self.line = Line(self, 2, style.padding.x) + + self.list_container = Widget(self) + self.list_container.border.width = 0 + self.list_container:set_size(200, 200) + + self.list = ListBox(self.list_container) + self.list.border.width = 0 + + self.list:enable_expand(true) + self.list:add_column("Num.") + self.list:add_column("Symbol") + self.list:add_column("Kind") + self.list:add_column("Location") + + local list_on_row_click = self.list.on_row_click + self.list.on_row_click = function(this, idx, data) + list_on_row_click(this, idx, data) + self:on_selected(idx, data) + end + + self.num = 1 + + self.border.width = 0 + self:set_size(200, 200) + self:show() +end + +function SymbolResults:add_result(result) + local preview, position = Lsp.get_location_preview(result.location) + local container_name = result.containerName and + result.containerName .. "\n" or "" + + local row = { + tostring(self.num), + ListBox.COLEND, + style.syntax.keyword, container_name .. result.name, + ListBox.COLEND, + style.syntax.literal, Server.get_symbol_kind(result.kind), + ListBox.COLEND, + style.text, position, ListBox.NEWLINE, style.accent, preview + } + + self.num = self.num + 1 + + self.list:add_row(row, result) +end + +function SymbolResults:stop_searching() + self.searching = false +end + +function SymbolResults:on_selected(idx, data) + Lsp.goto_location(data.location) +end + +function SymbolResults:update() + if not SymbolResults.super.update(self) then return end + -- update the positions and sizes + self.background_color = style.background + self.title:set_position(style.padding.x, style.padding.y) + if not self.searching or #self.list.rows > 0 then + local label = "Finished: " + if self.searching then + label = "Searching: " + end + self.title:set_label( + label + .. #self.list.rows + .. " results found for " + .. '"' + .. self.symbol + .. '"' + ) + end + self.line:set_position(0, self.title:get_bottom() + 10) + self.list_container:set_position(style.padding.x, self.line:get_bottom() + 10) + self.list_container:set_size( + self.size.x - (style.padding.x * 2), + self.size.y - self.line:get_bottom() + ) +end + + +return SymbolResults + diff --git a/debian/extra/plugins/lsp/timer.lua b/debian/extra/plugins/lsp/timer.lua new file mode 100644 index 0000000..c25fefa --- /dev/null +++ b/debian/extra/plugins/lsp/timer.lua @@ -0,0 +1,101 @@ +local core = require "core" +local Object = require "core.object" + +---Timer class +---@class lsp.timer : core.object +---@field public interval integer +---@field public single_shot boolean +---@field private started boolean +---@field private last_run integer +local Timer = Object:extend() + +---Constructor +---@param interval integer The interval in milliseconds +---@param single_shot boolean Indicates if timer should only run once +function Timer:new(interval, single_shot) + Timer.super.new(self) + + self.single_shot = single_shot or false + self.started = false + self.cancel_thread_marker = { cancel = true } + self.last_run = 0 + + self:set_interval(interval or 1000) +end + +---Starts a non running timer. +function Timer:start() + if self.started then return end + + self.started = true + self.cancel_thread_marker = { cancel = false } + local this = self + + -- Save marker so that we keep this one and not an "updated" one + local marker = self.cancel_thread_marker + core.add_thread(function() + while true do + if marker.cancel == true then return end + this:reset() + local now = system.get_time() + local remaining = (this.last_run + this.interval) - now + if remaining > 0 then + repeat + if not this.started or marker.cancel then return end + coroutine.yield(remaining) + now = system.get_time() + remaining = (this.last_run + this.interval) - now + until remaining <= 0 + end + if not this.started or marker.cancel then return end + this:on_timer() + if this.single_shot then break end + end + this.started = false + end) +end + +---Stops a running timer. +function Timer:stop() + self.started = false +end + +---Resets the timer countdown for execution. +function Timer:reset() + self.last_run = system.get_time() +end + +---Restarts the timer countdown for execution. +function Timer:restart() + self:reset() + if not self.started then + self:start() + end +end + +---Check if the timer is running. +---@return boolean +function Timer:running() + return self.started +end + +---Appropriately set the timer interval by converting milliseconds to seconds. +---@param interval integer The interval in milliseconds +function Timer:set_interval(interval) + local new_interval = interval / 1000 + -- As this new interval might be shorter than the currently running one, and + -- because we might already be sleeping waiting for the old interval, we + -- mark the already running coroutine as cancelled, and create a new one. + if self.started and self.interval > new_interval then + self.cancel_thread_marker.cancel = true + self:stop() + self:start() + end + self.interval = new_interval +end + +---To be overwritten by the instantiated timer objects +function Timer:on_timer() end + + +return Timer diff --git a/debian/extra/plugins/lsp/util.lua b/debian/extra/plugins/lsp/util.lua new file mode 100644 index 0000000..588c101 --- /dev/null +++ b/debian/extra/plugins/lsp/util.lua @@ -0,0 +1,474 @@ +-- Some functions adapted from: https://github.com/orbitalquark/textadept-lsp +-- and others added as needed. +-- +-- @copyright Jefferson Gonzalez +-- @license MIT + +local core = require "core" +local common = require "core.common" +local config = require "core.config" +local json = require "plugins.lsp.json" + +local util = {} + +---Check if the given file is currently opened on the editor. +---@param abs_filename string +function util.doc_is_open(abs_filename) + -- Normalize path format to the one used by normal docs + abs_filename = common.normalize_path(abs_filename) or abs_filename + for _, doc in ipairs(core.docs) do + ---@cast doc core.doc + if doc.abs_filename == abs_filename then + return true; + end + end + return false +end + +---Converts a utf-8 column position into the equivalent utf-16 position. +---@param doc core.doc +---@param line integer +---@param column integer +---@return integer col_position +function util.doc_utf8_to_utf16(doc, line, column) + local ltext = doc.lines[line] + local ltext_len = ltext and #ltext or 0 + local ltext_ulen = ltext and utf8extra.len(ltext) or 0 + column = common.clamp(column, 1, ltext_len > 0 and ltext_len or 1) + -- no need for conversion so return column as is + if ltext_len == ltext_ulen then return column end + if column > 1 then + local col = 1 + for pos, code in utf8extra.next, ltext do + if pos >= column then + return col + end + -- Codepoints that high are encoded using surrogate pairs + if code < 0x010000 then + col = col + 1 + else + col = col + 2 + end + end + return col + end + return column +end + +---Converts a utf-16 column position into the equivalent utf-8 position. +---@param doc core.doc +---@param line integer +---@param column integer +---@return integer col_position +function util.doc_utf16_to_utf8(doc, line, column) + local ltext = doc.lines[line] + local ltext_len = ltext and #ltext or 0 + local ltext_ulen = ltext and utf8extra.len(ltext) or 0 + column = common.clamp(column, 1, ltext_len > 0 and ltext_len or 1) + -- no need for conversion so return column as is + if ltext_len == ltext_ulen then return column end + if column > 1 then + local col = 1 + local utf8_pos = 1 + for pos, code in utf8extra.next, ltext do + if col >= column then + return pos + end + utf8_pos = pos + -- Codepoints that high are encoded using surrogate pairs + if code < 0x010000 then + col = col + 1 + else + col = col + 2 + end + end + return utf8_pos + end + return column +end + +---Split a string by the given delimeter +---@param s string The string to split +---@param delimeter string Delimeter without lua patterns +---@param delimeter_pattern? string Optional delimeter with lua patterns +---@return table +---@return boolean ends_with_delimiter +function util.split(s, delimeter, delimeter_pattern) + if not delimeter_pattern then + delimeter_pattern = delimeter + end + + local last_idx = 1 + local result = {} + for match_idx, afer_match_idx in s:gmatch("()"..delimeter_pattern.."()") do + table.insert(result, string.sub(s, last_idx, match_idx - 1)) + last_idx = afer_match_idx + end + if last_idx > #s then + return result, true + else + table.insert(result, string.sub(s, last_idx)) + return result, false + end +end + +---Get the extension component of a filename. +---@param filename string +---@return string +function util.file_extension(filename) + local parts = util.split(filename, "%.") + if #parts > 1 then + return parts[#parts]:gsub("%%", "") + end + + return filename +end + +---Check if a file exists. +---@param file_path string +---@return boolean +function util.file_exists(file_path) + local file = io.open(file_path, "r") + if file ~= nil then + file:close() + return true + end + return false +end + +---Converts the given LSP DocumentUri into a valid filename path. +---@param uri string LSP DocumentUri to convert into a filename. +---@return string +function util.tofilename(uri) + local filename = "" + if PLATFORM == "Windows" then + filename = uri:gsub('^file:///', '') + else + filename = uri:gsub('^file://', '') + end + + filename = filename:gsub( + '%%(%x%x)', + function(hex) return string.char(tonumber(hex, 16)) end + ) + + if PLATFORM == "Windows" then filename = filename:gsub('/', '\\') end + + return filename +end + +---Convert a file path to a LSP valid uri. +---@param file_path string +---@return string +function util.touri(file_path) + local function char_escape(char) + if string.match(char, "[_.~-]") then return char end + if char == "/" then return char end + if char == "\\" and PLATFORM == "Windows" then return "/" end + return string.format("%%%02X", string.byte(char)) + end + + file_path = string.gsub(file_path, "([%W ])", char_escape) + if PLATFORM ~= "Windows" then + file_path = 'file://' .. file_path + else + file_path = 'file:///' .. file_path:gsub('\\', '/') + end + + return file_path +end + +---Converts a document range returned by lsp to a valid document selection. +---@param range table LSP Range. +---@param doc? core.doc +---@return integer line1 +---@return integer col1 +---@return integer line2 +---@return integer col2 +function util.toselection(range, doc) + local line1 = range.start.line + 1 + local col1 = range.start.character + 1 + local line2 = range['end'].line + 1 + local col2 = range['end'].character + 1 + + if doc then + col1 = util.doc_utf16_to_utf8(doc, line1, col1) + col2 = util.doc_utf16_to_utf8(doc, line2, col2) + end + + return line1, col1, line2, col2 +end + +---Opens the given location on a external application. +---@param location string +function util.open_external(location) + local filelauncher = "" + if PLATFORM == "Windows" then + filelauncher = "start" + elseif PLATFORM == "Mac OS X" then + filelauncher = "open" + else + filelauncher = "xdg-open" + end + + -- non-Windows platforms need the text quoted (%q) + if PLATFORM ~= "Windows" then + location = string.format("%q", location) + end + + system.exec(filelauncher .. " " .. location) +end + +---Prettify json output and logs it if config.lsp.log_file is set. +---@param code string +---@return string +function util.jsonprettify(code) + if config.plugins.lsp.prettify_json then + code = json.prettify(code) + end + + if config.plugins.lsp.log_file and #config.plugins.lsp.log_file > 0 then + local log = io.open(config.plugins.lsp.log_file, "a+") + log:write("Output: \n" .. tostring(code) .. "\n\n") + log:close() + end + + return code +end + +---Gets the last component of a path. For example: +---/my/path/to/somwhere would return somewhere. +---@param path string +---@return string +function util.getpathname(path) + local components = {} + if PLATFORM == "Windows" then + components = util.split(path, "\\") + else + components = util.split(path, "/") + end + + if #components > 0 then + return components[#components] + end + + return path +end + +---Check if a value is on a table. +---@param value any +---@param table_array table +---@return boolean +function util.intable(value, table_array) + for _, element in pairs(table_array) do + if element == value then + return true + end + end + + return false +end + +---Remove by key from a table and returns a new +---table with element removed. +---@param table_object table +---@param key_name string|integer +---@return table +function util.table_remove_key(table_object, key_name) + local new_table = {} + for key, data in pairs(table_object) do + if key ~= key_name then + new_table[key] = data + end + end + + return new_table +end + +---Get a table specific field or nil if not found. +---@param t table The table we are going to search for the field. +---@param fieldset string A field spec in the format +---"parent[.child][.subchild]" eg: "myProp.subProp.subSubProp" +---@return any|nil The value of the given field or nil if not found. +function util.table_get_field(t, fieldset) + local fields = util.split(fieldset, ".", "%.") + local field = fields[1] + local value = nil + + if field and #fields > 1 and t[field] then + local sub_fields = table.concat(fields, ".", 2) + value = util.table_get_field(t[field], sub_fields) + elseif field and #fields > 0 and t[field] then + value = t[field] + end + + return value +end + +---Merge the content of the tables into a new one. +---Arguments from the later tables take precedence. +---Doesn't touch the original tables. +---`nil` arguments are ignored. +---@param ... table? +---@return table +function util.deep_merge(...) + local t = {} + local args = table.pack(...) + for i=1,args.n do + local other = args[i] + if other then + assert(type(other) == "table", string.format("Argument %d must be a table", i)) + for k, v in pairs(other) do + if type(v) == "table" then + if type(t[k]) == "table" then + t[k] = util.deep_merge(t[k], v) + else + t[k] = util.deep_merge({}, v) + end + else + t[k] = v + end + end + end + end + return t +end + +---Check if a table is really empty. +---@param t table +---@return boolean +function util.table_empty(t) + return next(t) == nil +end + +---Convert markdown to plain text. +---@param text string +---@return string +function util.strip_markdown(text) + local clean_text = "" + local prev_line = "" + for match in (text.."\n"):gmatch("(.-)".."\n") do + match = match .. "\n" + + -- strip markdown + local new_line = match + -- Block quotes + :gsub("^>+(%s*)", "%1") + -- headings + :gsub("^(%s*)######%s(.-)\n", "%1%2\n") + :gsub("^(%s*)#####%s(.-)\n", "%1%2\n") + :gsub("^(%s*)####%s(.-)\n", "%1%2\n") + :gsub("^(%s*)####%s(.-)\n", "%1%2\n") + :gsub("^(%s*)###%s(.-)\n", "%1%2\n") + :gsub("^(%s*)##%s(.-)\n", "%1%2\n") + :gsub("^(%s*)#%s(.-)\n", "%1%2\n") + -- heading custom id + :gsub("{#.-}", "") + -- emoji + :gsub(":[%w%-_]+:", "") + -- bold and italic + :gsub("%*%*%*(.-)%*%*%*", "%1") + :gsub("___(.-)___", "%1") + :gsub("%*%*_(.-)_%*%*", "%1") + :gsub("__%*(.-)%*__", "%1") + :gsub("___(.-)___", "%1") + -- bold + :gsub("%*%*(.-)%*%*", "%1") + :gsub("__(.-)__", "%1") + -- strikethrough + :gsub("%-%-(.-)%-%-", "%1") + -- italic + :gsub("%*(.-)%*", "%1") + :gsub("%s_(.-)_%s", "%1") + :gsub("\\_(.-)\\_", "_%1_") + :gsub("^_(.-)_", "%1") + -- code + :gsub("^%s*```(%w+)%s*\n", "") + :gsub("^%s*```%s*\n", "") + :gsub("``(.-)``", "%1") + :gsub("`(.-)`", "%1") + -- lines + :gsub("^%-%-%-%-*%s*\n", "") + :gsub("^%*%*%*%**%s*\n", "") + -- reference links + :gsub("^%[[^%^](.-)%]:.-\n", "") + -- footnotes + :gsub("^%[%^(.-)%]:%s+", "[%1]: ") + :gsub("%[%^(.-)%]", "[%1]") + -- Images + :gsub("!%[(.-)%]%((.-)%)", "") + -- links + :gsub("%s<(.-)>%s", "%1") + :gsub("%[(.-)%]%s*%[(.-)%]", "%1") + :gsub("%[(.-)%]%((.-)%)", "%1: %2") + -- remove escaped punctuations + :gsub("\\(%p)", "%1") + + -- if paragraph put in same line + local is_paragraph = false + + local prev_spaces = prev_line:match("^%g+") + local prev_endings = prev_line:match("[ \t\r\n]+$") + local new_spaces = new_line:match("^%g+") + + if prev_spaces and new_spaces then + local new_lines = prev_endings ~= nil + and prev_endings:gsub("[ \t\r]+", "") or "" + + if #new_lines == 1 then + is_paragraph = true + clean_text = clean_text:gsub("[%s\n]+$", "") + .. " " .. new_line:gsub("^%s+", "") + end + end + + if not is_paragraph then + clean_text = clean_text .. new_line + end + + prev_line = new_line + end + return clean_text +end + +---@param text string +---@param font renderer.font +---@param max_width number +function util.wrap_text(text, font, max_width) + local lines = util.split(text, "\n") + local wrapped_text = "" + local longest_line = 0; + for _, line in ipairs(lines) do + local line_len = line:ulen() or 0 + if line_len > longest_line then + longest_line = line_len + local line_width = font:get_width(line) + if line_width > max_width then + local words = util.split(line, " ") + local new_line = words[1] and words[1] or "" + wrapped_text = wrapped_text .. new_line + for w=2, #words do + if font:get_width(new_line .. " " .. words[w]) <= max_width then + new_line = new_line .. " " .. words[w] + wrapped_text = wrapped_text .. " " .. words[w] + else + wrapped_text = wrapped_text .. "\n" .. words[w] + new_line = words[w] + end + end + wrapped_text = wrapped_text .. "\n" + else + wrapped_text = wrapped_text .. line .. "\n" + end + else + wrapped_text = wrapped_text .. line .. "\n" + end + end + + wrapped_text = wrapped_text:gsub("\n\n\n\n?", "\n\n"):gsub("%s*$", "") + + return wrapped_text +end + + +return util diff --git a/debian/extra/plugins/nerdicons.lua b/debian/extra/plugins/nerdicons.lua new file mode 100644 index 0000000..c26c8f2 --- /dev/null +++ b/debian/extra/plugins/nerdicons.lua @@ -0,0 +1,210 @@ +-- mod-version:3 +-- Orginal Author: Jipok +-- Modified by: techie-guy +-- Doesn't work well with scaling mode == "ui" + +-- This is an extension/modification of the nonicons plugin, https://github.com/lite-xl/lite-xl-plugins/blob/master/plugins/nonicons.lua + +-- Any icon can be searched with nerdfonts.com/cheat-sheet + +local common = require "core.common" +local config = require "core.config" +local style = require "core.style" +local TreeView = require "plugins.treeview" +local Node = require "core.node" + +local nerdfonts_symbols = require "libraries.font_symbols_nerdfont_mono_regular" + +-- Config +config.plugins.nerdicons = common.merge({ + use_default_dir_icons = false, + use_default_chevrons = false, + draw_treeview_icons = true, + draw_tab_icons = true, + -- The config specification used by the settings gui + config_spec = { + name = "Nerdicons", + { + label = "Use Default Directory Icons", + description = "When enabled does not use nerdicon directory icons.", + path = "use_default_dir_icons", + type = "toggle", + default = false + }, + { + label = "Use Default Chevrons", + description = "When enabled does not use nerdicon expand/collapse arrow icons.", + path = "use_default_chevrons", + type = "toggle", + default = false + }, + { + label = "Draw Treeview Icons", + description = "Enables file related icons on the treeview.", + path = "draw_treeview_icons", + type = "toggle", + default = true + }, + { + label = "Draw Tab Icons", + description = "Adds file related icons to tabs.", + path = "draw_tab_icons", + type = "toggle", + default = true + }, + } +}, config.plugins.nerdicons) + +local icon_font = renderer.font.load(nerdfonts_symbols.path, 18.5 * SCALE) +local map = nerdfonts_symbols.utf8 +local chevron_width = icon_font:get_width(map["oct-chevron_down"]) +local previous_scale = SCALE + + +local extension_icons = { + [".hxml"] = { "#d3d3d3", "seti-config" }, -- Haxe + [".hx"] = { "#f68712", "seti-haxe" }, + [".d"] = { "#ff3333", "dev-dlang" }, -- D + [".di"] = { "#ff6666", "dev-dlang" }, + [".lua"] = { "#405af0", "seti-lua" }, + [".md"] = { "#519aba", "dev-markdown" }, -- Markdown + [".powershell"] = { "#519aba", "cod-terminal_powershell" }, + [".bat"] = { "#cbcb41", "cod-terminal_cmd" }, + [".txt"] = { "#ffffff", "fa-file_text" }, + [".cpp"] = { "#519aba", "custom-cpp" }, + [".c"] = { "#599eff", "custom-c" }, + [".h"] = { "#79029b", "fa-header" }, + [".hpp"] = { "#79029b", "fa-header" }, + [".py"] = { "#3572A5", "md-language_python" }, -- Python + [".pyc"] = { "#519aba", "md-language_python" }, + [".pyd"] = { "#519aba", "md-language_python" }, + [".php"] = { "#a074c4", "md-language_php" }, + [".cs"] = { "#596706", "md-language_csharp" }, -- C# + [".conf"] = { "#6d8086", "seti-config" }, + [".cfg"] = { "#6d8086", "seti-config" }, + [".toml"] = { "#6d8086", "seti-config" }, + [".yaml"] = { "#6d8086", "seti-yml" }, + [".yml"] = { "#6d8086", "seti-yml" }, + [".json"] = { "#854CC7", "seti-json" }, + [".css"] = { "#519abc", "dev-css3" }, + [".html"] = { "#e34c26", "dev-html5" }, + [".js"] = { "#cbcb41", "dev-javascript_badge" }, + [".cjs"] = { "#cbcb41", "dev-javascript_badge" }, + [".mjs"] = { "#cbcb41", "dev-javascript_badge" }, -- JavaScript + [".ejs"] = { "#ffea7f", "seti-ejs" }, + [".pug"] = { "#a86454", "seti-pug" }, + [".go"] = { "#519aba", "seti-go" }, + [".jpg"] = { "#a074c4", "fa-image" }, + [".png"] = { "#a074c4", "fa-image" }, + [".sh"] = { "#4d5a5e", "cod-terminal_bash" }, + [".bash"] = { "#4d5a5e", "cod-terminal_bash" }, -- Shell + [".java"] = { "#cc3e44", "dev-java" }, + [".scala"] = { "#cc3e44", "dev-scala" }, + [".kt"] = { "#F88A02", "custom-kotlin" }, -- Kotlin + [".pl"] = { "#519aba", "dev-perl" }, -- Perl + [".pm"] = { "#519aba", "dev-perl" }, -- Perl + [".rb"] = { "#701516", "dev-ruby_rough" }, -- Ruby + [".rs"] = { "#c95625", "dev-rust" }, -- Rust + [".rss"] = { "#cc3e44", "fa-rss_square" }, + [".sql"] = { "#dad8d8", "dev-sqllite" }, + [".swift"] = { "#e37933", "dev-swift" }, + [".ts"] = { "#519aba", "md-language_typescript" }, -- TypeScript + [".diff"] = { "#41535b", "oct-diff" }, + [".exe"] = { "#cc3e55", "cod-file_binary" }, + [".make"] = { "#d0bf41", "dev-gnu" }, + [".svg"] = { "#f7ca39", "md-svg" }, + [".ttf"] = { "#dad8d4", "fa-font" }, + [".otf"] = { "#dad8d4", "fa-font" }, + [".vim"] = { "#8f00ff", "custom-vim" }, + [".pdf"] = { "#E53935", "fa-file_pdf_o" }, + [".jl"] = { "#4063d8", "seti-julia" }, + [".mp4"] = { "#e85e00", "oct-video" }, + [".jld2"] = { "#888888", "fa-database" }, + [".ipynb"] = { "#F37726", "seti-notebook" }, +} + + +local known_filenames_icons = { + ["dockerfile"] = { "#296478", "linux-docker" }, + [".gitignore"] = { "#cc3e55", "dev-git" }, + [".gitmodules"] = { "#cc3e56", "dev-git" }, + ["PKGBUILD"] = { "#6d8ccc", "md-package" }, + ["license"] = { "#d0bf41", "seti-license" }, + ["copying"] = { "#d0bf41", "seti-license" }, + ["makefile"] = { "#d0bf41", "dev-gnu" }, + ["cmakelists.txt"] = { "#cc3e55", "md-triangle_outline" }, +} + +-- Preparing colors +for _, v in pairs(extension_icons) do + v[1] = { common.color(v[1]) } +end +for _, v in pairs(known_filenames_icons) do + v[1] = { common.color(v[1]) } +end + +-- Override function to change default icons for dirs, special extensions and names +local TreeView_get_item_icon = TreeView.get_item_icon +function TreeView:get_item_icon(item, active, hovered) + local icon, font, color = TreeView_get_item_icon(self, item, active, hovered) + if previous_scale ~= SCALE then + icon_font:set_size( + icon_font:get_size() * (SCALE / previous_scale) + ) + chevron_width = icon_font:get_width(map["oct-chevron_down"]) + previous_scale = SCALE + end + if not config.plugins.nerdicons.use_default_dir_icons then + icon = map["cod-file"] -- hex ea7b + font = icon_font + color = style.text + if item.type == "dir" then + icon = item.expanded and map["fa-folder_open"] or map["fa-folder"] -- hex f07c and f07b + end + end + if config.plugins.nerdicons.draw_treeview_icons then + local custom_icon = known_filenames_icons[item.name:lower()] + if custom_icon == nil then + custom_icon = extension_icons[item.name:match("^.+(%..+)$")] + end + if custom_icon ~= nil then + color = custom_icon[1] + icon = map[custom_icon[2]] + font = icon_font + end + if active or hovered then + color = style.accent + end + end + return icon, font, color +end + +-- Override function to draw chevrons if setting is disabled +local TreeView_draw_item_chevron = TreeView.draw_item_chevron +function TreeView:draw_item_chevron(item, active, hovered, x, y, w, h) + if not config.plugins.nerdicons.use_default_chevrons then + if item.type == "dir" then + local chevron_icon = item.expanded and "oct-chevron_down" or "oct-chevron_right" + local chevron_color = hovered and style.accent or style.text + common.draw_text(icon_font, chevron_color, map[chevron_icon], nil, x+8, y, 0, h) -- added 8 to x to draw the chevron closer to the icon + end + return chevron_width + style.padding.x + end + return TreeView_draw_item_chevron(self, item, active, hovered, x, y, w, h) +end + +-- Override function to draw icons in tabs titles if setting is enabled +local Node_draw_tab_title = Node.draw_tab_title +function Node:draw_tab_title(view, font, is_active, is_hovered, x, y, w, h) + if config.plugins.nerdicons.draw_tab_icons then + local padx = chevron_width + style.padding.x/2 + local tx = x + padx/16 -- Space for icon + w = w + padx + Node_draw_tab_title(self, view, font, is_active, is_hovered, tx, y, w, h) + if (view == nil) or (view.doc == nil) then return end + local item = { type = "file", name = view.doc:get_name() } + TreeView:draw_item_icon(item, false, is_hovered, x, y, w, h) + else + Node_draw_tab_title(self, view, font, is_active, is_hovered, x, y, w, h) + end +end diff --git a/debian/extra/plugins/open_ext.lua b/debian/extra/plugins/open_ext.lua new file mode 100644 index 0000000..4c57d68 --- /dev/null +++ b/debian/extra/plugins/open_ext.lua @@ -0,0 +1,162 @@ +-- mod-version:3 + +-- The general idea is to check if the file opened is valid utf-8 +-- since lite-xl only supports UTF8 text, others can be safely assumed +-- to be binary +local core = require "core" +local common = require "core.common" +local style = require "core.style" +local DocView = require "core.docview" +local RootView = require "core.rootview" +local View = require "core.view" + + +local function validate_utf8(s, max_len) + local i, p, len = 1, 1, #s + while p <= len and i <= max_len do + if p == s:find("[%z\1-\127]", p) then p = p + 1 + elseif p == s:find("[\194-\223][\128-\191]", p) then p = p + 2 + elseif p == s:find( "\224[\160-\191][\128-\191]", p) + or p == s:find("[\225-\236][\128-\191][\128-\191]", p) + or p == s:find( "\237[\128-\159][\128-\191]", p) + or p == s:find("[\238-\239][\128-\191][\128-\191]", p) then p = p + 3 + elseif p == s:find( "\240[\144-\191][\128-\191][\128-\191]", p) + or p == s:find("[\241-\243][\128-\191][\128-\191][\128-\191]", p) + or p == s:find( "\244[\128-\143][\128-\191][\128-\191]", p) then p = p + 4 + else + return false + end + i = i + 1 + end + return true +end + + +local function replace_view(this, that) + local node = core.root_view.root_node:get_node_for_view(this) + local idx = node:get_view_idx(this) + node:remove_view(core.root_view.root_node, this) + node:add_view(that, idx) + core.root_view.root_node:update_layout() + core.redraw = true +end + + +local msg = "This file is not displayed because it is either binary or uses an unsupported text encoding." +local cmd -- here's evil code again... +if PLATFORM == "Windows" then + cmd = "start %q" +elseif PLATFORM == "Linux" then + cmd = "xdg-open %q" +else + cmd = "open %q" +end + +local opt = { "Open anyway", "Open with other program", "Close" } +local opt_actions = { + function(self) + -- open anyway + local view = DocView(core.open_doc(self.filename)) + replace_view(self, view) + end, + function(self) + -- open externally + local node = core.root_view.root_node:get_node_for_view(self) + node:close_view(core.root_view.root_node, self) + system.exec(string.format(cmd, self.filename)) + end, + function(self) + local node = core.root_view.root_node:get_node_for_view(self) + node:close_view(core.root_view.root_node, self) + end +} + + +local OpenExtView = View:extend() + + +function OpenExtView:new(filename) + OpenExtView.super.new(self) + self.filename = filename +end + + +function OpenExtView:get_name() + return common.basename(self.filename) +end + + +function OpenExtView:each_option() + return coroutine.wrap(function() + local w = (self.size.x - style.padding.x * (#opt + 1)) / #opt + local h = style.font:get_height() + style.padding.y + local x, y = self:get_content_offset() + x = x + style.padding.x + y = y + self.size.y / 2 + style.padding.y + for i, o in ipairs(opt) do + coroutine.yield(i, o, x, y, w, h) + x = x + w + style.padding.x + end + end) +end + + +function OpenExtView:on_mouse_moved(px, py, dx, dy) + OpenExtView.super.on_mouse_moved(self, px, py, dx, dy) + self.hovered = nil + for i, _, x, y, w, h in self:each_option() do + if px > x and px <= x + w and py > y and py <= y + h then + self.hovered = i + break + end + end +end + + +function OpenExtView:on_mouse_pressed(button, x, y, clicks) + if OpenExtView.super.on_mouse_pressed(self, button, x, y, clicks) then return end + if self.hovered then + opt_actions[self.hovered](self) + end +end + + +function OpenExtView:draw() + self:draw_background(style.background) + local x, y = self:get_content_offset() + local lh = style.font:get_height() + y = y + self.size.y / 2 - style.padding.y - lh + common.draw_text(style.font, style.text, msg, "center", x, y, self.size.x, lh) + for i, opt, x, y, w, h in self:each_option() do + local text_color = i == self.hovered and style.background or style.text + renderer.draw_rect(x, y, w, h, style.accent) + if i ~= self.hovered then + renderer.draw_rect(x + 1, y + 1, w - 2, h - 2, style.background) + end + common.draw_text(style.font, text_color, opt, "center", x, y, w, h) + end +end + + +local function validate_doc(doc) + local f = io.open(doc.abs_filename or "") + if not f then return true end + local str = f:read(128 * 4) -- max bytes for 128 codepoints + f:close() + return validate_utf8(str or "", 128) +end + + +local rootview_open_doc = RootView.open_doc +function RootView:open_doc(doc) + -- 128 * 4 == max number of bytes for 128 codepoints + if validate_doc(doc) then + return rootview_open_doc(self, doc) + else + local node = self:get_active_node_default() + local view = OpenExtView(doc.abs_filename or doc.filename) + node:add_view(view) + self.root_node:update_layout() + return view + end +end diff --git a/debian/extra/plugins/select_colorscheme.lua b/debian/extra/plugins/select_colorscheme.lua new file mode 100644 index 0000000..6fa45d4 --- /dev/null +++ b/debian/extra/plugins/select_colorscheme.lua @@ -0,0 +1,132 @@ +-- mod-version:3 +local core = require "core" +local command = require "core.command" +local common = require "core.common" +local style = require "core.style" +local CommandView = require "core.commandview" + +-- ---------------------------------------------------------------- +local PATH_CONFIG = USERDIR .. "/color_settings.lua" + +local Settings = {} +Settings.color_scheme = "" +Settings.color_list = {} +local color_default = {name = "Default", module = "core.style"} +local plugin_enable = false + +-- =========================Proxy method========================== +local move_suggestion_idx = CommandView.move_suggestion_idx + +function CommandView:move_suggestion_idx(dir) + move_suggestion_idx(self, dir) + if plugin_enable then + local color_name = self.suggestions[self.suggestion_idx].text + Settings:change_color(color_name) + end +end + +local on_quit_project = core.on_quit_project + +function core.on_quit_project() + Settings:save_settings() + on_quit_project() +end +-- ---------------------------------------------------------------- + +function Settings:get_color_list() + return self.color_list +end + +function Settings:init() + self:load_settings() + self:make_color_list() +end + +function Settings:make_color_list() + for _, root_dir in ipairs {DATADIR, USERDIR} do + local plugin_dir = root_dir .. "/colors" + for _, filename in ipairs(system.list_dir(plugin_dir) or {}) do + table.insert(self.color_list, filename:match("(.-)%.lua$")) + end + end + table.insert(self.color_list, color_default.name) +end + +function Settings:is_change_color(color_name) + return not (self.color_scheme == color_name) +end + +function Settings:get_color_scheme() + return (self.color_scheme == "") and color_default.name or self.color_scheme +end + +local function make_color_module_name(name) + return (name == color_default.name) and color_default.module or "colors."..name +end + +function Settings:change_color(name) + if self:is_change_color(name) then + core.reload_module(make_color_module_name(name)) + self.color_scheme = name + end +end + +function Settings:save_settings() + local fp = io.open(PATH_CONFIG, "w") + if fp then + fp:write(self.color_scheme) + fp:close() + end +end + +function Settings:load_settings() + local fp = io.open(PATH_CONFIG, "r") + if fp then + local name = fp:read("*a") + if name and name ~= "" then + core.reload_module(make_color_module_name(name)) + Settings.color_scheme = name + end + fp:close() + end +end + +-- -------------------------------Utility-------------------------- +local function table_remove_value(list, value) + for i=1, #list do + if list[i] == value then + table.remove(list, i) + break + end + end +end +-- ---------------------------------------------------------------- +local function normalize_color_list(list) + table_remove_value(list, Settings:get_color_scheme()) + table.sort(list, function(a, b) return string.lower(a) > string.lower(b) end) + return {Settings:get_color_scheme(), table.unpack(list)} +end +-- =========================Add Commands========================== +local color_scheme_submit = function(text, item) + if item then + Settings:change_color(item.text) + plugin_enable = false + end +end + +local color_scheme_suggest = function(text) + plugin_enable = true + local res_list = common.fuzzy_match(Settings:get_color_list(), text) + return normalize_color_list(res_list) +end + +command.add(nil, { + ["ui:color scheme"] = function() + core.command_view:enter("Select color scheme", { + submit = color_scheme_submit, suggest = color_scheme_suggest + }) + end, +}) +-- ---------------------------------------------------------------- + +Settings:init() diff --git a/debian/extra/plugins/settings.lua b/debian/extra/plugins/settings.lua new file mode 100644 index 0000000..2b947ca --- /dev/null +++ b/debian/extra/plugins/settings.lua @@ -0,0 +1,1982 @@ +-- mod-version:3 --priority:0 +local core = require "core" +local config = require "core.config" +local common = require "core.common" +local command = require "core.command" +local keymap = require "core.keymap" +local style = require "core.style" +local View = require "core.view" +local DocView = require "core.docview" + +-- check if widget is installed before proceeding +local widget_found, Widget = pcall(require, "libraries.widget") +if not widget_found then + core.error("Widget library not found: https://github.com/lite-xl/lite-xl-widgets") + return false +end + +local Label = require "libraries.widget.label" +local Line = require "libraries.widget.line" +local NoteBook = require "libraries.widget.notebook" +local Button = require "libraries.widget.button" +local TextBox = require "libraries.widget.textbox" +local SelectBox = require "libraries.widget.selectbox" +local NumberBox = require "libraries.widget.numberbox" +local Toggle = require "libraries.widget.toggle" +local ListBox = require "libraries.widget.listbox" +local FoldingBook = require "libraries.widget.foldingbook" +local FontsList = require "libraries.widget.fontslist" +local ItemsList = require "libraries.widget.itemslist" +local KeybindingDialog = require "libraries.widget.keybinddialog" +local Fonts = require "libraries.widget.fonts" +local FilePicker = require "libraries.widget.filepicker" +local ColorPicker = require "libraries.widget.colorpicker" +local MessageBox = require "libraries.widget.messagebox" + +---@class plugins.settings +local settings = {} + +settings.core = {} +settings.plugins = {} +settings.sections = {} +settings.plugin_sections = {} +settings.config = {} +settings.default_keybindings = {} + +---Enumeration for the different types of settings. +---@type table +settings.type = { + STRING = 1, + NUMBER = 2, + TOGGLE = 3, + SELECTION = 4, + LIST_STRINGS = 5, + BUTTON = 6, + FONT = 7, + FILE = 8, + DIRECTORY = 9, + COLOR = 10 +} + +---@alias settings.types +---| `settings.type.STRING` +---| `settings.type.NUMBER` +---| `settings.type.TOGGLE` +---| `settings.type.SELECTION` +---| `settings.type.LIST_STRINGS` +---| `settings.type.BUTTON` +---| `settings.type.FONT` +---| `settings.type.FILE` +---| `settings.type.DIRECTORY` +---| `settings.type.COLOR` + +---Represents a setting to render on a settings pane. +---@class settings.option +---Title displayed to the user eg: "My Option" +---@field public label string +---Description of the option eg: "Modifies the document indentation" +---@field public description string +---Config path in the config table, eg: section.myoption, myoption, etc... +---@field public path string +---Type of option that will be used to render an appropriate control +---@field public type settings.types | integer +---Default value of the option +---@field public default string | number | boolean | table | table +---Used for NUMBER to indicate the minimum number allowed +---@field public min number +---Used for NUMBER to indiciate the maximum number allowed +---@field public max number +---Used for NUMBER to indiciate the increment/decrement amount +---@field public step number +---Used in a SELECTION to provide the list of valid options +---@field public values table +---Optionally used for FONT to store the generated font group. +---@field public fonts_list table +---Flag set to true when loading user defined fonts fail +---@field public font_error boolean +---Optional function that is used to manipulate the current value on retrieval. +---@field public get_value nil | fun(value:any):any +---Optional function that is used to manipulate the saved value on save. +---@field public set_value nil | fun(value:any):any +---The icon set for a BUTTON +---@field public icon string +---Command or function executed when a BUTTON is clicked +---@field public on_click nil | string | fun(button:string, x:integer, y:integer) +---Optional function executed when the option value is applied. +---@field public on_apply nil | fun(value:any) +---When FILE or DIRECTORY this flag tells the path should exist. +---@field public exists boolean +---Lua patterns used on FILE or DIRECTORY to filter browser results and +---also force the selection to match one of the filters. +---@field public filters table + +---Add a new settings section to the settings UI +---@param section string +---@param options settings.option[] +---@param plugin_name? string Optional name of plugin +---@param overwrite? boolean Overwrite previous section options +function settings.add(section, options, plugin_name, overwrite) + local category = "" + if plugin_name ~= nil then + category = "plugins" + else + category = "core" + end + + if overwrite and settings[category][section] then + settings[category][section] = {} + end + + if not settings[category][section] then + settings[category][section] = {} + if category ~= "plugins" then + table.insert(settings.sections, section) + else + table.insert(settings.plugin_sections, section) + end + end + + if plugin_name ~= nil then + if not settings[category][section][plugin_name] then + settings[category][section][plugin_name] = {} + end + for _, option in ipairs(options) do + table.insert(settings[category][section][plugin_name], option) + end + else + for _, option in ipairs(options) do + table.insert(settings[category][section], option) + end + end +end + +-------------------------------------------------------------------------------- +-- Add Core Settings +-------------------------------------------------------------------------------- + +settings.add("General", + { + { + label = "User Module", + description = "Open your init.lua for customizations.", + type = settings.type.BUTTON, + icon = "P", + on_click = "core:open-user-module" + }, + { + label = "Clear Fonts Cache", + description = "Delete current font cache and regenerate a fresh one.", + type = settings.type.BUTTON, + icon = "C", + on_click = function() + if Fonts.cache_is_building() then + MessageBox.warning( + "Clear Fonts Cache", + { "The font cache is already been built,\n" + .. "status will be logged on the core log." + } + ) + else + MessageBox.info( + "Clear Fonts Cache", + { "Re-building the font cache can take some time,\n" + .. "it is needed when you have installed new fonts\n" + .. "which are not listed on the font picker tool.\n\n" + .. "Do you want to continue?" + }, + function(_, button_id, _) + if button_id == 1 then + Fonts.clean_cache() + end + end, + MessageBox.BUTTONS_YES_NO + ) + end + end + }, + { + label = "Maximum Project Files", + description = "The maximum amount of project files to register.", + path = "max_project_files", + type = settings.type.NUMBER, + default = 2000, + min = 1, + max = 100000, + on_apply = function() + core.rescan_project_directories() + end + }, + { + label = "File Size Limit", + description = "The maximum file size in megabytes allowed for editing.", + path = "file_size_limit", + type = settings.type.NUMBER, + default = 10, + min = 1, + max = 50 + }, + { + label = "Ignore Files", + description = "List of lua patterns matching files to be ignored by the editor.", + path = "ignore_files", + type = settings.type.LIST_STRINGS, + default = { + -- folders + "^%.svn/", "^%.git/", "^%.hg/", "^CVS/", "^%.Trash/", "^%.Trash%-.*/", + "^node_modules/", "^%.cache/", "^__pycache__/", + -- files + "%.pyc$", "%.pyo$", "%.exe$", "%.dll$", "%.obj$", "%.o$", + "%.a$", "%.lib$", "%.so$", "%.dylib$", "%.ncb$", "%.sdf$", + "%.suo$", "%.pdb$", "%.idb$", "%.class$", "%.psd$", "%.db$", + "^desktop%.ini$", "^%.DS_Store$", "^%.directory$", + }, + on_apply = function() + core.rescan_project_directories() + end + }, + { + label = "Maximum Clicks", + description = "The maximum amount of consecutive clicks that are registered by the editor.", + path = "max_clicks", + type = settings.type.NUMBER, + default = 3, + min = 1, + max = 10 + }, + } +) + +settings.add("Graphics", + { + { + label = "Frames Per Second", + description = "Lower value for low end machines and higher for a smoother experience.", + path = "fps", + type = settings.type.NUMBER, + default = 60, + min = 10, + max = 300 + }, + { + label = "Transitions", + description = "If disabled turns off all transitions but improves rendering performance.", + path = "transitions", + type = settings.type.TOGGLE, + default = true + }, + { + label = "Animation Rate", + description = "The amount of time it takes for a transition to finish.", + path = "animation_rate", + type = settings.type.NUMBER, + default = 1.0, + min = 0.5, + max = 3.0, + step = 0.1 + }, + { + label = "Animate Mouse Drag Scroll", + description = "Causes higher cpu usage but smoother scroll transition.", + path = "animate_drag_scroll", + type = settings.type.TOGGLE, + default = false + }, + { + label = "Disable Scrolling Transitions", + path = "disabled_transitions.scroll", + type = settings.type.TOGGLE, + default = false + }, + { + label = "Disable Command View Transitions", + path = "disabled_transitions.commandview", + type = settings.type.TOGGLE, + default = false + }, + { + label = "Disable Context Menu Transitions", + path = "disabled_transitions.contextmenu", + type = settings.type.TOGGLE, + default = false + }, + { + label = "Disable Log View Transitions", + path = "disabled_transitions.logview", + type = settings.type.TOGGLE, + default = false + }, + { + label = "Disable Nag Bar Transitions", + path = "disabled_transitions.nagbar", + type = settings.type.TOGGLE, + default = false + }, + { + label = "Disable Tab Transitions", + path = "disabled_transitions.tabs", + type = settings.type.TOGGLE, + default = false + }, + { + label = "Disable Tab Drag Transitions", + path = "disabled_transitions.tab_drag", + type = settings.type.TOGGLE, + default = false + }, + { + label = "Disable Status Bar Transitions", + path = "disabled_transitions.statusbar", + type = settings.type.TOGGLE, + default = false + }, + } +) + +settings.add("User Interface", + { + { + label = "Font", + description = "The font and fallbacks used on non code text.", + path = "font", + type = settings.type.FONT, + fonts_list = style, + default = { + fonts = { + { + name = "Fira Sans Regular", + path = DATADIR .. "/fonts/FiraSans-Regular.ttf" + } + }, + options = { + size = 15, + antialiasing = "subpixel", + hinting = "slight" + } + } + }, + { + label = "Borderless", + description = "Use built-in window decorations.", + path = "borderless", + type = settings.type.TOGGLE, + default = false, + on_apply = function() + core.configure_borderless_window() + end + }, + { + label = "Always Show Tabs", + description = "Shows tabs even if a single document is opened.", + path = "always_show_tabs", + type = settings.type.TOGGLE, + default = true + }, + { + label = "Maximum Tabs", + description = "The maximum amount of visible document tabs.", + path = "max_tabs", + type = settings.type.NUMBER, + default = 8, + min = 1, + max = 100 + }, + { + label = "Close Button on Tabs", + description = "Display the close button on tabs.", + path = "tab_close_button", + type = settings.type.TOGGLE, + default = true + }, + { + label = "Mouse wheel scroll rate", + description = "The amount to scroll when using the mouse wheel.", + path = "mouse_wheel_scroll", + type = settings.type.NUMBER, + default = 50, + min = 10, + max = 200, + get_value = function(value) + return value / SCALE + end, + set_value = function(value) + return value * SCALE + end + }, + { + label = "Force Scrollbar Status", + description = "Choose a fixed scrollbar state instead of resizing it on mouse hover.", + path = "force_scrollbar_status", + type = settings.type.SELECTION, + default = false, + values = { + {"Disabled", false}, + {"Expanded", "expanded"}, + {"Contracted", "contracted"} + }, + on_apply = function(value) + local mode = config.force_scrollbar_status_mode or "global" + local globally = mode == "global" + local views = core.root_view.root_node:get_children() + for _, view in ipairs(views) do + if globally or view:extends(DocView) then + view.h_scrollbar:set_forced_status(value) + view.v_scrollbar:set_forced_status(value) + else + view.h_scrollbar:set_forced_status(false) + view.v_scrollbar:set_forced_status(false) + end + end + end + }, + { + label = "Force Scrollbar Status Mode", + description = "Choose between applying globally or document views only.", + path = "force_scrollbar_status_mode", + type = settings.type.SELECTION, + default = "global", + values = { + {"Documents", "docview"}, + {"Globally", "global"} + }, + on_apply = function(value) + local globally = value == "global" + local views = core.root_view.root_node:get_children() + for _, view in ipairs(views) do + if globally or view:extends(DocView) then + view.h_scrollbar:set_forced_status(config.force_scrollbar_status) + view.v_scrollbar:set_forced_status(config.force_scrollbar_status) + else + view.h_scrollbar:set_forced_status(false) + view.v_scrollbar:set_forced_status(false) + end + end + end + }, + { + label = "Disable Cursor Blinking", + description = "Disables cursor blinking on text input elements.", + path = "disable_blink", + type = settings.type.TOGGLE, + default = false + }, + { + label = "Cursor Blinking Period", + description = "Interval in seconds in which the cursor blinks.", + path = "blink_period", + type = settings.type.NUMBER, + default = 0.8, + min = 0.3, + max = 2.0, + step = 0.1 + } + } +) + +settings.add("Editor", + { + { + label = "Code Font", + description = "The font and fallbacks used on the code editor.", + path = "code_font", + type = settings.type.FONT, + fonts_list = style, + default = { + fonts = { + { + name = "JetBrains Mono Regular", + path = DATADIR .. "/fonts/JetBrainsMono-Regular.ttf" + } + }, + options = { + size = 15, + antialiasing = "subpixel", + hinting = "slight" + } + } + }, + { + label = "Indentation Type", + description = "The character inserted when pressing the tab key.", + path = "tab_type", + type = settings.type.SELECTION, + default = "soft", + values = { + {"Space", "soft"}, + {"Tab", "hard"} + } + }, + { + label = "Indentation Size", + description = "Amount of spaces shown per indentation.", + path = "indent_size", + type = settings.type.NUMBER, + default = 2, + min = 1, + max = 10 + }, + { + label = "Keep Newline Whitespace", + description = "Do not remove whitespace when pressing enter.", + path = "keep_newline_whitespace", + type = settings.type.TOGGLE, + default = false + }, + { + label = "Line Limit", + description = "Amount of characters at which the line breaking column will be drawn.", + path = "line_limit", + type = settings.type.NUMBER, + default = 80, + min = 1 + }, + { + label = "Line Height", + description = "The amount of spacing between lines.", + path = "line_height", + type = settings.type.NUMBER, + default = 1.2, + min = 1.0, + max = 3.0, + step = 0.1 + }, + { + label = "Highlight Line", + description = "Highlight the current line.", + path = "highlight_current_line", + type = settings.type.SELECTION, + default = true, + values = { + {"Yes", true}, + {"No", false}, + {"No Selection", "no_selection"} + }, + set_value = function(value) + if type(value) == "nil" then return false end + return value + end + }, + { + label = "Maximum Undo History", + description = "The amount of undo elements to keep.", + path = "max_undos", + type = settings.type.NUMBER, + default = 10000, + min = 100, + max = 100000 + }, + { + label = "Undo Merge Timeout", + description = "Time in seconds before applying an undo action.", + path = "undo_merge_timeout", + type = settings.type.NUMBER, + default = 0.3, + min = 0.1, + max = 1.0, + step = 0.1 + }, + { + label = "Symbol Pattern", + description = "A lua pattern used to match symbols in the document.", + path = "symbol_pattern", + type = settings.type.STRING, + default = "[%a_][%w_]*" + }, + { + label = "Non Word Characters", + description = "A string of characters that do not belong to a word.", + path = "non_word_chars", + type = settings.type.STRING, + default = " \\t\\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-", + get_value = function(value) + return value:gsub("\n", "\\n"):gsub("\t", "\\t") + end, + set_value = function(value) + return value:gsub("\\n", "\n"):gsub("\\t", "\t") + end + }, + { + label = "Scroll Past the End", + description = "Allow scrolling beyond the document ending.", + path = "scroll_past_end", + type = settings.type.TOGGLE, + default = true + } + } +) + +settings.add("Development", + { + { + label = "Core Log", + description = "Open the list of logged messages.", + type = settings.type.BUTTON, + icon = "f", + on_click = "core:open-log" + }, + { + label = "Log Items", + description = "The maximum amount of entries to keep on the log UI.", + path = "max_log_items", + type = settings.type.NUMBER, + default = 800, + min = 150, + max = 2000 + }, + { + label = "Skip Plugins Version", + description = "Do not verify the plugins required versions at startup.", + path = "skip_plugins_version", + type = settings.type.TOGGLE, + default = false + } + } +) + +settings.add("Status Bar", + { + { + label = "Enabled", + description = "Toggle the default visibility of the status bar.", + path = "statusbar.enabled", + type = settings.type.TOGGLE, + default = true, + on_apply = function(enabled) + if enabled then + core.status_view:show() + else + core.status_view:hide() + end + end + }, + { + label = "Show Notifications", + description = "Toggle the visibility of status messages.", + path = "statusbar.messages", + type = settings.type.TOGGLE, + default = true, + on_apply = function(enabled) + core.status_view:display_messages(enabled) + end + }, + { + label = "Messages Timeout", + description = "The amount in seconds before a notification dissapears.", + path = "message_timeout", + type = settings.type.NUMBER, + default = 5, + min = 1, + max = 30 + } + } +) + +---Retrieve from given config the associated value using the given path. +---@param conf table +---@param path string +---@param default any +---@return any | nil +local function get_config_value(conf, path, default) + local sections = {}; + for match in (path.."."):gmatch("(.-)%.") do + table.insert(sections, match); + end + + local element = conf + for _, section in ipairs(sections) do + if type(element[section]) ~= "nil" then + element = element[section] + else + return default + end + end + + if type(element) == "nil" then + return default + end + + return element +end + +---Loops the given config table using the given path and store the value. +---@param conf table +---@param path string +---@param value any +local function set_config_value(conf, path, value) + local sections = {}; + for match in (path.."."):gmatch("(.-)%.") do + table.insert(sections, match); + end + + local sections_count = #sections + + if sections_count == 1 then + conf[sections[1]] = value + return + elseif type(conf[sections[1]]) ~= "table" then + conf[sections[1]] = {} + end + + local element = conf + for idx, section in ipairs(sections) do + if type(element[section]) ~= "table" then + element[section] = {} + element = element[section] + else + element = element[section] + end + if idx + 1 == sections_count then break end + end + + element[sections[sections_count]] = value +end + +---Get a list of system and user installed plugins. +---@return table +local function get_installed_plugins() + local files, ordered = {}, {} + + for _, root_dir in ipairs {DATADIR, USERDIR} do + local plugin_dir = root_dir .. "/plugins" + for _, filename in ipairs(system.list_dir(plugin_dir) or {}) do + local valid = false + local file_info = system.get_file_info(plugin_dir .. "/" .. filename) + if file_info then + if + file_info.type == "file" + and + filename:match("%.lua$") + and + not filename:match("^language_") + then + valid = true + filename = filename:gsub("%.lua$", "") + elseif file_info.type == "dir" then + if system.get_file_info(plugin_dir .. "/" .. filename .. "/init.lua") then + valid = true + end + end + end + if valid then + if not files[filename] then table.insert(ordered, filename) end + files[filename] = true + end + end + end + + table.sort(ordered) + + return ordered +end + +---Get a list of system and user installed colors. +---@return table +local function get_installed_colors() + local files, ordered = {}, {} + + for _, root_dir in ipairs {DATADIR, USERDIR} do + local dir = root_dir .. "/colors" + for _, filename in ipairs(system.list_dir(dir) or {}) do + local file_info = system.get_file_info(dir .. "/" .. filename) + if + file_info and file_info.type == "file" + and + filename:match("%.lua$") + then + -- read colors + local contents = io.open(dir .. "/" .. filename):read("*a") + local colors = {} + for r, g, b in contents:gmatch("#(%x%x)(%x%x)(%x%x)") do + r = tonumber(r, 16) + g = tonumber(g, 16) + b = tonumber(b, 16) + table.insert(colors, { r, g, b, 0xff }) + end + -- sort colors from darker to lighter + table.sort(colors, function(a, b) + return a[1] + a[2] + a[3] < b[1] + b[2] + b[3] + end) + -- remove duplicate colors + local b = {} + for i = #colors, 1, -1 do + local a = colors[i] + if a[1] == b[1] and a[2] == b[2] and a[3] == b[3] then + table.remove(colors, i) + else + b = colors[i] + end + end + -- insert color to ordered table if not duplicate + filename = filename:gsub("%.lua$", "") + if not files[filename] then + table.insert(ordered, {name = filename, colors = colors}) + end + files[filename] = true + end + end + end + + table.sort(ordered, function(a, b) return a.name < b.name end) + + return ordered +end + +---Capitalize first letter of every word. +---Taken from core.command. +---@param words string +---@return string +local function capitalize_first(words) + return words:sub(1, 1):upper() .. words:sub(2) +end + +---Similar to command prettify_name but also takes care of underscores. +---@param name string +---@return string +local function prettify_name(name) + name = name:gsub("[%-_]", " "):gsub("%S+", capitalize_first) + return name +end + +---Load config options from the USERDIR user_settings.lua and store them on +---settings.config for later usage. +local function load_settings() + local ok, t = pcall(dofile, USERDIR .. "/user_settings.lua") + settings.config = ok and t.config or {} +end + +---Save current config options into the USERDIR user_settings.lua +local function save_settings() + local fp = io.open(USERDIR .. "/user_settings.lua", "w") + if fp then + local output = "{\n [\"config\"] = " + .. common.serialize( + settings.config, + { pretty = true, escape = true, sort = true, initial_indent = 1 } + ):gsub("^%s+", "") + .. "\n}\n" + fp:write("return ", output) + fp:close() + end +end + +---Apply a keybinding and optionally save it. +---@param cmd string +---@param bindings table +---@param skip_save? boolean +---@return table | nil +local function apply_keybinding(cmd, bindings, skip_save) + local row_value = nil + local changed = false + + local original_bindings = { keymap.get_binding(cmd) } + for _, binding in ipairs(original_bindings) do + keymap.unbind(binding, cmd) + end + + if #bindings > 0 then + if + not skip_save + and + settings.config.custom_keybindings + and + settings.config.custom_keybindings[cmd] + then + settings.config.custom_keybindings[cmd] = {} + end + local shortcuts = "" + for _, binding in ipairs(bindings) do + if not binding:match("%+$") and binding ~= "" and binding ~= "none" then + keymap.add({[binding] = cmd}) + shortcuts = shortcuts .. binding .. "\n" + if not skip_save then + if not settings.config.custom_keybindings then + settings.config.custom_keybindings = {} + settings.config.custom_keybindings[cmd] = {} + elseif not settings.config.custom_keybindings[cmd] then + settings.config.custom_keybindings[cmd] = {} + end + table.insert(settings.config.custom_keybindings[cmd], binding) + changed = true + end + end + end + if shortcuts ~= "" then + local bindings_list = shortcuts:gsub("\n$", "") + row_value = { + style.text, cmd, ListBox.COLEND, style.dim, bindings_list + } + end + elseif + not skip_save + and + settings.config.custom_keybindings + and + settings.config.custom_keybindings[cmd] + then + settings.config.custom_keybindings[cmd] = nil + changed = true + end + + if changed then + save_settings() + end + + if not row_value then + row_value = { + style.text, cmd, ListBox.COLEND, style.dim, "none" + } + end + + return row_value +end + +---Load the saved fonts into the config path or fonts_list table. +---@param option settings.option +---@param path string +---@param saved_value any +local function merge_font_settings(option, path, saved_value) + local font_options = saved_value.options or { + size = 15, + antialiasing = "supixel", + hinting = "slight" + } + font_options.size = font_options.size or 15 + font_options.antialiasing = font_options.antialiasing or "subpixel" + font_options.hinting = font_options.hinting or "slight" + + local fonts = {} + local font_loaded = true + for _, font in ipairs(saved_value.fonts) do + local font_data = nil + font_loaded = core.try(function() + font_data = renderer.font.load( + font.path, font_options.size * SCALE, font_options + ) + end) + if font_loaded then + table.insert(fonts, font_data) + else + option.font_error = true + core.error("Settings: could not load %s\n'%s - %s'", path, font.name, font.path) + break + end + end + + if font_loaded then + if option.fonts_list then + set_config_value(option.fonts_list, option.path, renderer.font.group(fonts)) + else + set_config_value(config, path, renderer.font.group(fonts)) + end + end +end + +---Load the user_settings.lua stored options for a plugin into global config. +---@param plugin_name string +---@param options settings.option[] +local function merge_plugin_settings(plugin_name, options) + for _, option in pairs(options) do + if type(option.path) == "string" then + local path = "plugins." .. plugin_name .. "." .. option.path + local saved_value = get_config_value(settings.config, path) + if type(saved_value) ~= "nil" then + if option.type == settings.type.FONT or option.type == "font" then + merge_font_settings(option, path, saved_value) + else + set_config_value(config, path, saved_value) + end + if option.on_apply then + option.on_apply(saved_value) + end + end + end + end +end + +---Merge previously saved settings without destroying the config table. +local function merge_settings() + if type(settings.config) ~= "table" then return end + + -- merge core settings + for _, section in ipairs(settings.sections) do + local options = settings.core[section] + for _, option in ipairs(options) do + if type(option.path) == "string" then + local saved_value = get_config_value(settings.config, option.path) + if type(saved_value) ~= "nil" then + if option.type == settings.type.FONT or option.type == "font" then + merge_font_settings(option, option.path, saved_value) + else + set_config_value(config, option.path, saved_value) + end + if option.on_apply then + option.on_apply(saved_value) + end + end + end + end + end + + -- merge plugin settings + table.sort(settings.plugin_sections) + for _, section in ipairs(settings.plugin_sections) do + local plugins = settings.plugins[section] + for plugin_name, options in pairs(plugins) do + merge_plugin_settings(plugin_name, options) + end + end + + -- apply custom keybindings + if settings.config.custom_keybindings then + for cmd, bindings in pairs(settings.config.custom_keybindings) do + apply_keybinding(cmd, bindings, true) + end + end +end + +---Scan all plugins to check if they define a config_spec and load it. +local function scan_plugins_spec() + for plugin, conf in pairs(config.plugins) do + if type(conf) == "table" and conf.config_spec then + settings.add( + conf.config_spec.name, + conf.config_spec, + plugin + ) + end + end +end + +---Called at core first run to store the default keybindings. +local function store_default_keybindings() + for name, _ in pairs(command.map) do + local keys = { keymap.get_binding(name) } + if #keys > 0 then + settings.default_keybindings[name] = keys + end + end +end + +---@class settings.ui : widget +---@field private notebook widget.notebook +---@field private core widget +---@field private colors widget +---@field private plugins widget +---@field private keybinds widget +---@field private about widget +---@field private core_sections widget.foldingbook +---@field private plugin_sections widget.foldingbook +local Settings = Widget:extend() + +---Constructor +function Settings:new() + Settings.super.new(self, nil, false) + + self.name = "Settings" + self.defer_draw = false + self.border.width = 0 + self.draggable = false + self.scrollable = false + + ---@type widget.notebook + self.notebook = NoteBook(self) + self.notebook.size.x = 250 + self.notebook.size.y = 300 + self.notebook.border.width = 0 + + self.core = self.notebook:add_pane("core", "Core") + self.colors = self.notebook:add_pane("colors", "Colors") + self.plugins = self.notebook:add_pane("plugins", "Plugins") + self.keybinds = self.notebook:add_pane("keybindings", "Keybindings") + self.about = self.notebook:add_pane("about", "About") + + self.notebook:set_pane_icon("core", "P") + self.notebook:set_pane_icon("colors", "W") + self.notebook:set_pane_icon("plugins", "B") + self.notebook:set_pane_icon("keybindings", "M") + self.notebook:set_pane_icon("about", "i") + + self.core_sections = FoldingBook(self.core) + self.core_sections.border.width = 0 + self.core_sections.scrollable = false + + self.plugin_sections = FoldingBook(self.plugins) + self.plugin_sections.border.width = 0 + self.plugin_sections.scrollable = false + + self:load_core_settings() + self:load_color_settings() + self:load_plugin_settings() + self:load_keymap_settings() + + self:setup_about() +end + +---Helper function to add control for both core and plugin settings. +---@oaram pane widget +---@param option settings.option +---@param plugin_name? string | nil +local function add_control(pane, option, plugin_name) + local found = false + local path = type(plugin_name) ~= "nil" and + "plugins." .. plugin_name .. "." .. option.path or option.path + local option_value = nil + if type(path) ~= "nil" then + option_value = get_config_value(config, path, option.default) + end + + if option.get_value then + option_value = option.get_value(option_value) + end + + ---@type widget + local widget = nil + + if type(option.type) == "string" then + option.type = settings.type[option.type:upper()] + end + + if option.type == settings.type.NUMBER then + ---@type widget.label + Label(pane, option.label .. ":") + ---@type widget.numberbox + local number = NumberBox(pane, option_value, option.min, option.max, option.step) + widget = number + found = true + + elseif option.type == settings.type.TOGGLE then + ---@type widget.toggle + local toggle = Toggle(pane, option.label, option_value) + widget = toggle + found = true + + elseif option.type == settings.type.STRING then + ---@type widget.label + Label(pane, option.label .. ":") + ---@type widget.textbox + local string = TextBox(pane, option_value or "") + widget = string + found = true + + elseif option.type == settings.type.SELECTION then + ---@type widget.label + Label(pane, option.label .. ":") + ---@type widget.selectbox + local select = SelectBox(pane) + for _, data in pairs(option.values) do + select:add_option(data[1], data[2]) + end + for idx, _ in ipairs(select.list.rows) do + if select.list:get_row_data(idx) == option_value then + select:set_selected(idx-1) + break + end + end + widget = select + found = true + + elseif option.type == settings.type.BUTTON then + ---@type widget.button + local button = Button(pane, option.label) + if option.icon then + button:set_icon(option.icon) + end + if option.on_click then + local command_type = type(option.on_click) + if command_type == "string" then + function button:on_click() + command.perform(option.on_click) + end + elseif command_type == "function" then + button.on_click = option.on_click + end + end + widget = button + found = true + + elseif option.type == settings.type.LIST_STRINGS then + ---@type widget.label + Label(pane, option.label .. ":") + ---@type widget.itemslist + local list = ItemsList(pane) + if type(option_value) == "table" then + for _, value in ipairs(option_value) do + list:add_item(value) + end + end + widget = list + found = true + + elseif option.type == settings.type.FONT then + --get fonts without conversion to renderer.font + if type(path) ~= "nil" then + if not option.font_error then + option_value = get_config_value(settings.config, path, option.default) + else + --fallback to default fonts if error loading user defined ones + option_value = option.default + end + end + ---@type widget.label + Label(pane, option.label .. ":") + ---@type widget.fontslist + local fonts = FontsList(pane) + if type(option_value) == "table" then + for _, font in ipairs(option_value.fonts) do + fonts:add_font(font) + end + + local font_options = option_value.options or { + size = 15, + antialiasing = "supixel", + hinting = "slight" + } + font_options.size = font_options.size or 15 + font_options.antialiasing = font_options.antialiasing or "subpixel" + font_options.hinting = font_options.hinting or "slight" + fonts:set_options(font_options) + end + widget = fonts + found = true + + elseif option.type == settings.type.FILE then + ---@type widget.label + Label(pane, option.label .. ":") + ---@type widget.filepicker + local file = FilePicker(pane, option_value or "") + if option.exists then + file:set_mode(FilePicker.mode.FILE_EXISTS) + else + file:set_mode(FilePicker.mode.FILE) + end + file.filters = option.filters or {} + widget = file + found = true + + elseif option.type == settings.type.DIRECTORY then + ---@type widget.label + Label(pane, option.label .. ":") + ---@type widget.filepicker + local file = FilePicker(pane, option_value or "") + if option.exists then + file:set_mode(FilePicker.mode.DIRECTORY_EXISTS) + else + file:set_mode(FilePicker.mode.DIRECTORY) + end + file.filters = option.filters or {} + widget = file + found = true + + elseif option.type == settings.type.COLOR then + ---@type widget.label + Label(pane, option.label .. ":") + ---@type widget.colorpicker + local color = ColorPicker(pane, option_value) + widget = color + found = true + end + + if widget and type(path) ~= "nil" then + function widget:on_change(value) + if self:is(SelectBox) then + value = self:get_selected_data() + elseif self:is(ItemsList) then + value = self:get_items() + elseif self:is(FontsList) then + value = { + fonts = self:get_fonts(), + options = self:get_options() + } + end + + if option.set_value then + value = option.set_value(value) + end + + if self:is(FontsList) then + local fonts = {} + for _, font in ipairs(value.fonts) do + table.insert(fonts, renderer.font.load( + font.path, value.options.size * SCALE, value.options + )) + end + if option.fonts_list then + set_config_value(option.fonts_list, path, renderer.font.group(fonts)) + else + set_config_value(config, path, renderer.font.group(fonts)) + end + else + set_config_value(config, path, value) + end + + set_config_value(settings.config, path, value) + save_settings() + if option.on_apply then + option.on_apply(value) + end + end + end + + if (option.description or option.default) and found then + local text = option.description or "" + local default = "" + local default_type = type(option.default) + if default_type ~= "table" and default_type ~= "nil" then + if text ~= "" then + text = text .. " " + end + default = string.format("(default: %s)", option.default) + end + ---@type widget.label + local description = Label(pane, text .. default) + description.desc = true + end +end + +---Generate all the widgets for core settings. +function Settings:load_core_settings() + for _, section in ipairs(settings.sections) do + local options = settings.core[section] + + ---@type widget|widget.foldingbook.pane|nil + local pane = self.core_sections:get_pane(section) + if not pane then + pane = self.core_sections:add_pane(section, section) + else + pane = pane.container + end + + for _, opt in ipairs(options) do + ---@type settings.option + local option = opt + add_control(pane, option) + end + end +end + +---Function in charge of rendering the colors column of the color pane. +---@param self widget.listbox +---@oaram row integer +---@param x integer +---@param y integer +---@param font renderer.font +---@param color renderer.color +---@param only_calc boolean +---@return number width +---@return number height +local function on_color_draw(self, row, x, y, font, color, only_calc) + local w = self:get_width() - (x - self.position.x) - style.padding.x + local h = font:get_height() + + if not only_calc then + local row_data = self:get_row_data(row) + local width = w/#row_data.colors + + for i = 1, #row_data.colors do + renderer.draw_rect(x + ((i - 1) * width), y, width, h, row_data.colors[i]) + end + end + + return w, h +end + +---Generate the list of all available colors with preview +function Settings:load_color_settings() + self.colors.scrollable = false + + local colors = get_installed_colors() + + ---@type widget.listbox + local listbox = ListBox(self.colors) + + listbox.border.width = 0 + listbox:enable_expand(true) + + listbox:add_column("Theme") + listbox:add_column("Colors") + + for idx, details in ipairs(colors) do + local name = details.name + if settings.config.theme and settings.config.theme == name then + listbox:set_selected(idx) + end + listbox:add_row({ + style.text, name, ListBox.COLEND, on_color_draw + }, {name = name, colors = details.colors}) + end + + function listbox:on_row_click(idx, data) + core.reload_module("colors." .. data.name) + settings.config.theme = data.name + save_settings() + end +end + +---Unload a plugin settings from plugins section. +---@param plugin string +function Settings:disable_plugin(plugin) + for _, section in ipairs(settings.plugin_sections) do + local plugins = settings.plugins[section] + + for plugin_name, options in pairs(plugins) do + if plugin_name == plugin then + self.plugin_sections:delete_pane(section) + end + end + end + + if + type(settings.config.enabled_plugins) == "table" + and + settings.config.enabled_plugins[plugin] + then + settings.config.enabled_plugins[plugin] = nil + end + if type(settings.config.disabled_plugins) ~= "table" then + settings.config.disabled_plugins = {} + end + + settings.config.disabled_plugins[plugin] = true + save_settings() +end + +---Load plugin and append its settings to the plugins section. +---@param plugin string +function Settings:enable_plugin(plugin) + local loaded = false + local config_type = type(config.plugins[plugin]) + if config_type == "boolean" or config_type == "nil" then + config.plugins[plugin] = {} + loaded = true + end + + require("plugins." .. plugin) + + if config.plugins[plugin] and config.plugins[plugin].config_spec then + local conf = config.plugins[plugin].config_spec + settings.add(conf.name, conf, plugin, true) + end + + for _, section in ipairs(settings.plugin_sections) do + local plugins = settings.plugins[section] + + for plugin_name, options in pairs(plugins) do + if plugin_name == plugin then + ---@type widget|widget.foldingbook.pane|nil + local pane = self.plugin_sections:get_pane(section) + if not pane then + pane = self.plugin_sections:add_pane(section, section) + else + pane = pane.container + end + + merge_plugin_settings(plugin, options) + + for _, opt in ipairs(options) do + ---@type settings.option + local option = opt + add_control(pane, option, plugin_name) + end + end + end + end + + if + type(settings.config.disabled_plugins) == "table" + and + settings.config.disabled_plugins[plugin] + then + settings.config.disabled_plugins[plugin] = nil + end + if type(settings.config.enabled_plugins) ~= "table" then + settings.config.enabled_plugins = {} + end + + settings.config.enabled_plugins[plugin] = true + save_settings() + + if loaded then + core.log("Loaded '%s' plugin", plugin) + end +end + +---Generate all the widgets for plugin settings. +function Settings:load_plugin_settings() + ---@type widget|widget.foldingbook.pane|nil + local pane = self.plugin_sections:get_pane("enable_disable") + if not pane then + pane = self.plugin_sections:add_pane("enable_disable", "Installed") + else + pane = pane.container + end + + -- requires earlier access to startup process + Label( + pane, + "Notice: disabling plugins will not take effect until next restart" + ) + + Line(pane, 2, 10) + + local plugins = get_installed_plugins() + for _, plugin in ipairs(plugins) do + if plugin ~= "settings" then + local enabled = false + + if + ( + type(config.plugins[plugin]) ~= "nil" + and + config.plugins[plugin] ~= false + ) + or + ( + settings.config.enabled_plugins + and + settings.config.enabled_plugins[plugin] + ) + then + enabled = true + end + + local this = self + + ---@type widget.toggle + local toggle = Toggle(pane, prettify_name(plugin), enabled) + function toggle:on_change(value) + if value then + this:enable_plugin(plugin) + else + this:disable_plugin(plugin) + end + end + end + end + + table.sort(settings.plugin_sections) + + for _, section in ipairs(settings.plugin_sections) do + local plugins = settings.plugins[section] + + for plugin_name, options in pairs(plugins) do + ---@type widget|widget.foldingbook.pane|nil + local pane = self.plugin_sections:get_pane(section) + if not pane then + pane = self.plugin_sections:add_pane(section, section) + else + pane = pane.container + end + + for _, opt in ipairs(options) do + ---@type settings.option + local option = opt + add_control(pane, option, plugin_name) + end + end + end +end + +---@type widget.keybinddialog +local keymap_dialog = KeybindingDialog() + +function keymap_dialog:on_save(bindings) + local row_value = apply_keybinding(self.command, bindings) + if row_value then + self.listbox:set_row(self.row_id, row_value) + end +end + +function keymap_dialog:on_reset() + local default_keys = settings.default_keybindings[self.command] + local current_keys = { keymap.get_binding(self.command) } + + for _, binding in ipairs(current_keys) do + keymap.unbind(binding, self.command) + end + + if default_keys and #default_keys > 0 then + local cmd = self.command + if not settings.config.custom_keybindings then + settings.config.custom_keybindings = {} + settings.config.custom_keybindings[cmd] = {} + elseif not settings.config.custom_keybindings[cmd] then + settings.config.custom_keybindings[cmd] = {} + end + local shortcuts = "" + for _, binding in ipairs(default_keys) do + keymap.add({[binding] = cmd}) + shortcuts = shortcuts .. binding .. "\n" + table.insert(settings.config.custom_keybindings[cmd], binding) + end + local bindings_list = shortcuts:gsub("\n$", "") + self.listbox:set_row(self.row_id, { + style.text, cmd, ListBox.COLEND, style.dim, bindings_list + }) + else + self.listbox:set_row(self.row_id, { + style.text, self.command, ListBox.COLEND, style.dim, "none" + }) + end + if + settings.config.custom_keybindings + and + settings.config.custom_keybindings[self.command] + then + settings.config.custom_keybindings[self.command] = nil + save_settings() + end +end + +---Generate the list of all available commands and allow editing their keymaps. +function Settings:load_keymap_settings() + self.keybinds.scrollable = false + + local ordered = {} + for name, _ in pairs(command.map) do + table.insert(ordered, name) + end + table.sort(ordered) + + ---@type widget.textbox + local textbox = TextBox(self.keybinds, "", "filter bindings...") + + ---@type widget.listbox + local listbox = ListBox(self.keybinds) + + listbox.border.width = 0 + + listbox:add_column("Command") + listbox:add_column("Bindings") + + for _, name in ipairs(ordered) do + local keys = { keymap.get_binding(name) } + local binding = "" + if #keys == 1 then + binding = keys[1] + elseif #keys > 1 then + binding = keys[1] + for idx, key in ipairs(keys) do + if idx ~= 1 then + binding = binding .. "\n" .. key + end + end + elseif #keys < 1 then + binding = "none" + end + listbox:add_row({ + style.text, name, ListBox.COLEND, style.dim, binding + }, name) + end + + function textbox:on_change(value) + listbox:filter(value) + end + + function listbox:on_mouse_pressed(button, x, y, clicks) + listbox.super.on_mouse_pressed(self, button, x, y, clicks) + local idx = listbox:get_selected() + local data = listbox:get_row_data(idx) + if clicks == 2 and not keymap_dialog:is_visible() then + local bindings = { keymap.get_binding(data) } + keymap_dialog:set_bindings(bindings) + keymap_dialog.row_id = idx + keymap_dialog.command = data + keymap_dialog.listbox = self + keymap_dialog:show() + end + end + + ---@param self widget + function self.keybinds:update_positions() + textbox:set_position(0, 0) + textbox:set_size(self:get_width() - self.border.width * 2) + listbox:set_position(0, textbox:get_bottom()) + listbox:set_size(self:get_width() - self.border.width * 2, self:get_height() - textbox:get_height()) + end +end + +function Settings:setup_about() + ---@type widget.label + local title = Label(self.about, "Lite XL") + title.font = "big_font" + ---@type widget.label + local version = Label(self.about, "version " .. VERSION) + ---@type widget.label + local description = Label( + self.about, + "A lightweight text editor written in Lua, adapted from lite." + ) + + local function open_link(link) + local platform_filelauncher + if PLATFORM == "Windows" then + platform_filelauncher = "start" + elseif PLATFORM == "Mac OS X" then + platform_filelauncher = "open" + else + platform_filelauncher = "xdg-open" + end + system.exec(platform_filelauncher .. " " .. link) + end + + ---@type widget.button + local button = Button(self.about, "Visit Website") + button:set_tooltip("Open https://lite-xl.com/") + function button:on_click() open_link("https://lite-xl.com/") end + + ---@type widget.listbox + local contributors = ListBox(self.about) + contributors.scrollable = true + contributors:add_column("Contributors") + contributors:add_column("") + contributors:add_column("Website") + function contributors:on_row_click(_, data) open_link(data) end + +local contributors_list = { + { "Rxi", "Lite Founder", "https://github.com/rxi" }, + { "Francesco Abbate", "Lite XL Founder", "https://github.com/franko" }, + { "Adam Harrison", "Core", "https://github.com/adamharrison" }, + { "Andrea Zanellato", "CI, Website", "https://github.com/redtide" }, + { "Björn Buckwalter", "MacOS Support", "https://github.com/bjornbm" }, + { "boppyt", "Contributor", "https://github.com/boppyt" }, + { "Cukmekerb", "Contributor", "https://github.com/vincens2005" }, + { "Daniel Rocha", "Contributor", "https://github.com/dannRocha" }, + { "daubaris", "Contributor", "https://github.com/daubaris" }, + { "Dheisom Gomes", "Contributor", "https://github.com/dheisom" }, + { "Evgeny Petrovskiy", "Contributor", "https://github.com/eugenpt" }, + { "Ferdinand Prantl", "Contributor", "https://github.com/prantlf" }, + { "Jan", "Build System", "https://github.com/Jan200101" }, + { "Janis-Leuenberger", "MacOS Support", "https://github.com/Janis-Leuenberger" }, + { "Jefferson", "Contributor", "https://github.com/jgmdev" }, + { "Jipok", "Contributor", "https://github.com/Jipok" }, + { "Joshua Minor", "Contributor", "https://github.com/jminor" }, + { "George Linkovsky", "Contributor", "https://github.com/Timofffee" }, + { "Guldoman", "Core", "https://github.com/Guldoman" }, + { "liquidev", "Contributor", "https://github.com/liquidev" }, + { "Mat Mariani", "MacOS Support", "https://github.com/mathewmariani" }, + { "Nightwing", "Contributor", "https://github.com/Nightwing13" }, + { "Nils Kvist", "Contributor", "https://github.com/budRich" }, + { "Not-a-web-Developer", "Contributor", "https://github.com/Not-a-web-Developer" }, + { "Robert Štojs", "CI", "https://github.com/netrobert" }, + { "sammyette", "Plugins", "https://github.com/TorchedSammy" }, + { "Takase", "Core", "https://github.com/takase1121" }, + { "xwii", "Contributor", "https://github.com/xcb-xwii" } +} + + for _, c in ipairs(contributors_list) do + contributors:add_row({ + c[1], ListBox.COLEND, c[2], ListBox.COLEND, c[3] + }, c[3]) + end + + ---@param self widget + function self.about:update_positions() + local center = self:get_width() / 2 + + title:set_label("Lite XL") + title:set_position( + center - (title:get_width() / 2), + style.padding.y + ) + + version:set_position( + center - (version:get_width() / 2), + title:get_bottom() + (style.padding.y / 2) + ) + + description:set_position( + center - (description:get_width() / 2), + version:get_bottom() + (style.padding.y / 2) + ) + + button:set_position( + center - (button:get_width() / 2), + description:get_bottom() + style.padding.y + ) + + contributors:set_position( + style.padding.x, + button:get_bottom() + style.padding.y + ) + + contributors:set_size( + self:get_width() - (style.padding.x * 2), + self:get_height() - (button:get_bottom() + (style.padding.y * 2)) + ) + + contributors:set_visible_rows() + end +end + +---Reposition and resize core and plugin widgets. +function Settings:update() + if not Settings.super.update(self) then return end + + self.notebook:set_size(self.size.x, self.size.y) + + for _, section in ipairs({self.core_sections, self.plugin_sections}) do + if section.parent:is_visible() then + section:set_size( + section.parent.size.x - (style.padding.x), + section:get_real_height() + ) + section:set_position(style.padding.x / 2, 0) + for _, pane in ipairs(section.panes) do + local prev_child = nil + for pos=#pane.container.childs, 1, -1 do + local child = pane.container.childs[pos] + local x, y = 10, (10 * SCALE) + if prev_child then + if + (prev_child:is(Label) and not prev_child.desc) + or + (child:is(Label) and child.desc) + then + y = prev_child:get_bottom() + (10 * SCALE) + else + y = prev_child:get_bottom() + (30 * SCALE) + end + end + if child:is(Line) then + x = 0 + elseif child:is(ItemsList) or child:is(FilePicker) or child:is(TextBox) then + child:set_size(pane.container:get_width() - 20, child.size.y) + end + child:set_position(x, y) + prev_child = child + end + end + end + end + + if self.keybinds:is_visible() then + self.keybinds:update_positions() + end + + if self.about:is_visible() then + self.about:update_positions() + end +end + +-------------------------------------------------------------------------------- +-- overwrite core run to inject previously saved settings +-------------------------------------------------------------------------------- +local core_run = core.run +function core.run() + store_default_keybindings() + + -- load plugins disabled by default and enabled by user + if settings.config.enabled_plugins then + for name, _ in pairs(settings.config.enabled_plugins) do + if not config.plugins[name] then + require("plugins." .. name) + end + end + end + + -- append all settings defined in the plugins spec + scan_plugins_spec() + + -- merge custom settings into config + merge_settings() + + ---@type settings.ui + settings.ui = Settings() + + -- apply user chosen color theme + if settings.config.theme and settings.config.theme ~= "default" then + core.try(function() + core.reload_module("colors." .. settings.config.theme) + end) + end + + -- re-apply user settings + core.load_user_directory() + core.load_project_module() + + core_run() +end + +-------------------------------------------------------------------------------- +-- Disable plugins at startup, only works if this file is the first +-- required on user module, or priority tag is obeyed by lite-xl. +-------------------------------------------------------------------------------- +-- load custom user settings that include list of disabled plugins +load_settings() + +-- only disable non already loaded plugins +if settings.config.disabled_plugins then + for name, _ in pairs(settings.config.disabled_plugins) do + if not package.loaded[name] then + config.plugins[name] = false + end + end +end + +-- properly apply skip_plugins_version before other plugins are loaded +if settings.config.skip_plugins_version then + config.skip_plugins_version = true +else + config.skip_plugins_version = false +end + +-------------------------------------------------------------------------------- +-- Add command and keymap to load settings view +-------------------------------------------------------------------------------- +command.add(nil, { + ["ui:settings"] = function() + settings.ui:show() + local node = core.root_view:get_active_node_default() + local found = false + for _, view in ipairs(node.views) do + if view == settings.ui then + found = true + node:set_active_view(view) + break + end + end + if not found then + node:add_view(settings.ui) + end + end, +}) + +keymap.add { + ["ctrl+alt+p"] = "ui:settings" +} + +-------------------------------------------------------------------------------- +-- Overwrite toolbar preferences command to open the settings gui +-------------------------------------------------------------------------------- +if config.plugins.toolbarview ~= false then + local ToolbarView = require "plugins.toolbarview" + local toolbarview_on_mouse_moved = ToolbarView.on_mouse_moved + function ToolbarView:on_mouse_moved(px, py, ...) + toolbarview_on_mouse_moved(self, px, py, ...) + if + self.hovered_item + and + self.hovered_item.command == "core:open-user-module" + then + self.hovered_item.command = "ui:settings" + end + end +end + +-------------------------------------------------------------------------------- +-- Overwrite View:new to allow setting force scrollbar status globally +-------------------------------------------------------------------------------- +local view_new = View.new +function View:new() + view_new(self) + local mode = config.force_scrollbar_status_mode or "global" + local globally = mode == "global" + if globally then + --This is delayed to allow widgets to also apply it to child views/widgets + core.add_thread(function() + self.v_scrollbar:set_forced_status(config.force_scrollbar_status) + self.h_scrollbar:set_forced_status(config.force_scrollbar_status) + end) + end +end + +return settings; diff --git a/debian/extra/plugins/smoothcaret.lua b/debian/extra/plugins/smoothcaret.lua new file mode 100644 index 0000000..86718de --- /dev/null +++ b/debian/extra/plugins/smoothcaret.lua @@ -0,0 +1,115 @@ +-- mod-version:3 +local core = require "core" +local config = require "core.config" +local style = require "core.style" +local common = require "core.common" +local DocView = require "core.docview" + +config.plugins.smoothcaret = common.merge({ + enabled = true, + rate = 0.65, + -- The config specification used by the settings gui + config_spec = { + name = "Smooth Caret", + { + label = "Enabled", + description = "Disable or enable the smooth caret animation.", + path = "enabled", + type = "toggle", + default = true + }, + { + label = "Rate", + description = "Speed of the animation.", + path = "rate", + type = "number", + default = 0.65, + min = 0.2, + max = 1.0, + step = 0.05 + }, + } +}, config.plugins.smoothcaret) + +local caret_idx = 1 + +local docview_update = DocView.update +function DocView:update() + docview_update(self) + + if not config.plugins.smoothcaret.enabled then return end + + local minline, maxline = self:get_visible_line_range() + + -- We need to keep track of all the carets + if not self.carets then + self.carets = { } + end + -- and we need the list of visible ones that `DocView:draw_caret` will use in succession + self.visible_carets = { } + + local idx, v_idx = 1, 1 + for _, line, col in self.doc:get_selections() do + local x, y = self:get_line_screen_position(line, col) + -- Keep the position relative to the whole View + -- This way scrolling won't animate the caret + x = x + self.scroll.x + y = y + self.scroll.y + + if not self.carets[idx] then + self.carets[idx] = { current = { x = x, y = y }, target = { x = x, y = y } } + end + + local c = self.carets[idx] + c.target.x = x + c.target.y = y + + -- Chech if the number of carets changed + if self.last_n_selections ~= #self.doc.selections then + -- Don't animate when there are new carets + c.current.x = x + c.current.y = y + else + self:move_towards(c.current, "x", c.target.x, config.plugins.smoothcaret.rate) + self:move_towards(c.current, "y", c.target.y, config.plugins.smoothcaret.rate) + end + + -- Keep track of visible carets + if line >= minline and line <= maxline then + self.visible_carets[v_idx] = self.carets[idx] + v_idx = v_idx + 1 + end + idx = idx + 1 + end + self.last_n_selections = #self.doc.selections + + -- Remove unused carets to avoid animating new ones when they are added + for i = idx, #self.carets do + self.carets[i] = nil + end + + if self.mouse_selecting ~= self.last_mouse_selecting then + self.last_mouse_selecting = self.mouse_selecting + -- Show the caret on click, so that it can be seen moving towards the new position + if self.mouse_selecting then + core.blink_timer = core.blink_timer + config.blink_period / 2 + core.redraw = true + end + end + + -- This is used by `DocView:draw_caret` to keep track of the current caret + caret_idx = 1 +end + +local docview_draw_caret = DocView.draw_caret +function DocView:draw_caret(x, y) + if not config.plugins.smoothcaret.enabled then + docview_draw_caret(self, x, y) + return + end + + local c = self.visible_carets[caret_idx] or { current = { x = x, y = y } } + docview_draw_caret(self, c.current.x - self.scroll.x, c.current.y - self.scroll.y) + + caret_idx = caret_idx + 1 +end diff --git a/debian/install b/debian/install index 7c3a5e6..58ae498 100644 --- a/debian/install +++ b/debian/install @@ -1,2 +1,118 @@ debian/extra/vscode_dark.lua usr/share/lite-xl/colors/ debian/extra/init.lua etc/skel/.config/lite-xl/ +debian/extra/plugins/lsp usr/share/lite-xl/plugins +debian/extra/libraries/widget usr/share/lite-xl/libraries +debian/extra/libraries/font_symbols_nerdfont_mono_regular.lua usr/share/lite-xl/libraries/ +debian/extra/fonts/SymbolsNerdFontMono-Regular.ttf usr/share/lite-xl/libraries/font_symbols_nerdfont_mono_regular/ +debian/extra/plugins/fontconfig.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/gitopen.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/gitstatus.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_R.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_angelscript.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_assembly_riscv.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_assembly_x86.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_autohotkey_v1.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_awk.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_batch.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_bend.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_bib.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_blade.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_blueprint.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_brainfuck.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_buzz.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_c7.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_caddyfile.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_carbon.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_clojure.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_cmake.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_csharp.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_cue.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_d.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_dart.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_diff.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_edp.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_ejs.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_elixir.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_elm.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_env.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_erb.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_fe.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_fennel.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_fortran.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_fstab.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_gabc.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_gdscript.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_glsl.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_gmi.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_go.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_graphql.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_gravity.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_groovy.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_hare.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_haxe.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_hlsl.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_hs.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_htaccess.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_ignore.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_ini.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_java.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_jiyu.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_json.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_jsx.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_julia.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_kdl.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_kotlin.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_lilypond.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_liquid.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_lobster.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_lox.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_make.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_marte.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_meson.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_miniscript.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_moon.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_nelua.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_nginx.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_nim.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_nix.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_objc.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_odin.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_openscad.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_perl.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_php.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_pico8.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_pkgbuild.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_po.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_powershell.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_psql.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_rescript.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_ring.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_rivet.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_ruby.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_rust.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_sass.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_scala.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_sh.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_ssh_config.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_st.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_starlark.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_swift.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_tal.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_tau.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_tcl.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_teal.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_tex.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_toml.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_ts.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_tsx.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_typst.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_umka.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_v.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_wren.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_yaml.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/language_zig.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/nerdicons.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/open_ext.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/select_colorscheme.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/settings.lua usr/share/lite-xl/plugins/ +debian/extra/plugins/smoothcaret.lua usr/share/lite-xl/plugins/