You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
7.0 KiB

  1. # Chroma Guide for F-Sy-H
  2. ## Motivation
  3. Someone might want to create a detailed highlighting for a **specific program**
  4. and this document helps achieving this. It explains how chroma functions – the
  5. code behind such detailed highlighting – are constructed and used.
  6. ## Keywords
  7. - `chroma` - a shorthand for `chroma function` – the thing that literally colorizes selected commands, like `git`, `grep`, etc. invocations, see `chroma function` below,
  8. - `big loop` - main highlighting code, a loop over tokens and at least 2 large structular constructs (big `if` and `case`);
  9. it is advanced, e.g. parses `case` statements, here-string, it basically constitutes 90% of the F-Sy-H project,
  10. - `chroma function` - a plugin-function that is called when a specific command occurs (e.g. when user enters `git` at
  11. command line) suppressing activity of `big loop` (i.e. no standard highlighting unless requested),
  12. - `token` - result of splitting whole command line (i.e. `$BUFFER`, the Zle variable) into bits called tokens, which are
  13. words in general, separated by spaces on the command line.
  14. ## Overview Of Functioning
  15. 1. Big loop is working – token by token processes command line, changes states (e.g. enters state "inside case
  16. statement") and in the end decides on color of the token currently processed.
  17. 2. Big loop occurs a command that has a chroma, e.g. `git`.
  18. 3. Big loop enters "chroma" state, calls associated chroma function.
  19. 4. Chroma takes care of "chroma" state, ensures it will be set also for next token.
  20. 5. "chroma" state is active, so all following tokens are routed to the chroma (in general skipping big-loop, see next items),
  21. 6. When processing of a single token is complete, the associated chroma returns 0
  22. (shell-truth) to request no further processing by the big loop.
  23. 7. It can also return 1 so that single, current token will be passed into big-loop
  24. for processing (to do a standard highlighting).
  25. ## Chroma-Function Arguments
  26. - `$1` - 0 or 1, denoting if it's the first call to the chroma, or a following one,
  27. - `$2` - the current token, also accessible by `$\__arg` from the upper scope -
  28. basically a private copy of `$__arg`; the token can be eg.: "grep",
  29. - `$3` - a private copy of `$_start_pos`, i.e. the position of the token in the
  30. command line buffer, used to add region_highlight entry (see man),
  31. because Zsh colorizes by *ranges* applied onto command line buffer (e.g.
  32. `from-10 to-13 fg=red`),
  33. - `$4` - a private copy of `$_end_pos` from the upper scope; denotes where current token
  34. ends (at which index in the string being the command line).
  35. So example invocation could look like this:
  36. ----
  37. chroma/-example.ch 1 "grep" "$_start_pos" "$_end_pos"
  38. ----
  39. Big-loop will be doing such calls for the user, after occurring a specific chroma-enabled command (like e.g. `awk`), and then until chroma will detect end of this chroma-enabled command (end of whole invocation, with arguments, etc.; in other words, when e.g. new line or `;`-character occurs, etc.).
  40. ## Example Chroma-Function
  41. [source,zsh]
  42. ----
  43. # -*- mode: sh; sh-indentation: 4; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
  44. # Copyright (c) 2018 Sebastian Gniazdowski
  45. #
  46. # Example chroma function. It colorizes first two arguments as `builtin' style,
  47. # third and following arguments as `globbing' style. First two arguments may
  48. # be "strings", they will be passed through to normal higlighter (by returning 1).
  49. #
  50. # $1 - 0 or 1, denoting if it's first call to the chroma, or following one
  51. #
  52. # $2 - like above document says
  53. #
  54. # $3 - ...
  55. #
  56. # $4 - ...
  57. #
  58. # Other tips are:
  59. # - $CURSOR holds cursor position
  60. # - $BUFFER holds whole command line buffer
  61. # - $LBUFFER holds command line buffer that is left from the cursor, i.e. it's a
  62. # BUFFER substring 1 .. $CURSOR
  63. # - $RBUFFER is the same as LBUFFER but holds part of BUFFER right to the cursor
  64. #
  65. # The function receives $BUFFER but via sequence of tokens, which are shell words,
  66. # e.g. "a b c" is a shell word, while a b c are 3 shell words.
  67. #
  68. # FAST_HIGHLIGHT is a friendly hash array which allows to store strings without
  69. # creating global parameters (variables). If you need hash, go ahead and use it,
  70. # declaring first, under some distinct name like: typeset -gA CHROMA_EXPLE_DICT.
  71. # Remember to reset the hash and others at __first_call == 1, so that you have
  72. # a fresh state for new command.
  73. # Keep chroma-takever state meaning: until ;, handle highlighting via chroma.
  74. # So the below 8192 assignment takes care that next token will be routed to chroma.
  75. (( next_word = 2 | 8192 ))
  76. local __first_call="$1" __wrd="$2" __start_pos="$3" __end_pos="$4"
  77. local __style
  78. integer __idx1 __idx2
  79. (( __first_call )) && {
  80. # Called for the first time - new command.
  81. # FAST_HIGHLIGHT is used because it survives between calls, and
  82. # allows to use a single global hash only, instead of multiple
  83. # global string variables.
  84. FAST_HIGHLIGHT[chroma-example-counter]=0
  85. # Set style for region_highlight entry. It is used below in
  86. # '[[ -n "$__style" ]] ...' line, which adds highlight entry,
  87. # like "10 12 fg=green", through `reply' array.
  88. #
  89. # Could check if command `example' exists and set `unknown-token'
  90. # style instead of `command'
  91. __style=${FAST_THEME_NAME}command
  92. } || {
  93. # Following call, i.e. not the first one
  94. # Check if chroma should end – test if token is of type
  95. # "starts new command", if so pass-through – chroma ends
  96. [[ "$__arg_type" = 3 ]] && return 2
  97. if [[ "$__wrd" = -* ]]; then
  98. # Detected option, add style for it.
  99. [[ "$__wrd" = --* ]] && __style=${FAST_THEME_NAME}double-hyphen-option || \
  100. __style=${FAST_THEME_NAME}single-hyphen-option
  101. else
  102. # Count non-option tokens
  103. (( FAST_HIGHLIGHT[chroma-example-counter] += 1, __idx1 = FAST_HIGHLIGHT[chroma-example-counter] ))
  104. # Colorize 1..2 as builtin, 3.. as glob
  105. if (( FAST_HIGHLIGHT[chroma-example-counter] <= 2 )); then
  106. if [[ "$__wrd" = \"* ]]; then
  107. # Pass through, fsh main code will do the highlight!
  108. return 1
  109. else
  110. __style=${FAST_THEME_NAME}builtin
  111. fi
  112. else
  113. __style=${FAST_THEME_NAME}globbing
  114. fi
  115. fi
  116. }
  117. # Add region_highlight entry (via `reply' array).
  118. # If 1 will be added to __start_pos, this will highlight "oken".
  119. # If 1 will be subtracted from __end_pos, this will highlight "toke".
  120. # $PREBUFFER is for specific situations when users does command \<ENTER>
  121. # i.e. when multi-line command using backslash is entered.
  122. #
  123. # This is a common place of adding such entry, but any above code can do
  124. # it itself (and it does in other chromas) and skip setting __style to
  125. # this way disable this code.
  126. [[ -n "$__style" ]] && (( __start=__start_pos-${#PREBUFFER}, __end=__end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
  127. # We aren't passing-through, do obligatory things ourselves.
  128. # _start_pos=$_end_pos advainces pointers in command line buffer.
  129. (( this_word = next_word ))
  130. _start_pos=$_end_pos
  131. return 0
  132. ----