init.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. -- Copyright 2007-2017 Mitchell mitchell.att.foicica.com. See LICENSE.
  2. local M = {}
  3. --[[ This comment is for LuaDoc.
  4. ---
  5. -- The css module.
  6. -- It provides utilities for editing CSS code.
  7. module('_M.css')]]
  8. -- Sets default buffer properties for CSS files.
  9. events.connect(events.LEXER_LOADED, function(lang)
  10. if lang == 'css' then
  11. buffer.word_chars =
  12. 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-'
  13. end
  14. end)
  15. -- Autocompletion and documentation.
  16. local completion = '%s'..string.char(buffer.auto_c_type_separator)..'%d'
  17. local XPM = textadept.editing.XPM_IMAGES
  18. -- List of selectors available for autocompletion.
  19. local selectors = {
  20. 'a', 'abbr', 'acronym', 'address', 'area', 'b', 'base', 'big', 'blockquote',
  21. 'body', 'br', 'button', 'caption', 'cite', 'code', 'col', 'colgroup', 'dd',
  22. 'del', 'dfn', 'div', 'dl', 'dt', 'em', 'fieldset', 'form', 'frame',
  23. 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html', 'i',
  24. 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'link',
  25. 'map', 'meta', 'noframes', 'noscript', 'object', 'ol', 'optgroup', 'option',
  26. 'p', 'param', 'pre', 'q', 'samp', 'script', 'select', 'small', 'span',
  27. 'strike', 'strong', 'style', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea',
  28. 'tfoot', 'th', 'thead', 'title', 'tr', 'tt', 'ul', 'var'
  29. }
  30. for i = 1, #selectors do
  31. selectors[i] = completion:format(selectors[i], XPM.CLASS)
  32. end
  33. -- List of properties available for autocompletion.
  34. local properties = {
  35. 'azimuth', 'background', 'background-attachment', 'background-color',
  36. 'background-image', 'background-position', 'background-repeat', 'border',
  37. 'border-bottom', 'border-bottom-color', 'border-bottom-style',
  38. 'border-bottom-width', 'border-collapse', 'border-color', 'border-left',
  39. 'border-left-color', 'border-left-style', 'border-left-width', 'border-right',
  40. 'border-right-color', 'border-right-style', 'border-right-width',
  41. 'border-spacing', 'border-style', 'border-top', 'border-top-color',
  42. 'border-top-style', 'border-top-width', 'border-width', 'bottom',
  43. 'caption-side', 'clear', 'clip', 'color', 'content', 'counter-increment',
  44. 'counter-reset', 'cue', 'cue-after', 'cue-before', 'cursor', 'direction',
  45. 'display', 'elevation', 'empty-cells', 'float', 'font', 'font-family',
  46. 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant',
  47. 'font-weight', 'height', 'left', 'letter-spacing', 'line-height',
  48. 'list-style', 'list-style-image', 'list-style-position', 'list-style-type',
  49. 'margin', 'margin-bottom', 'margin-left', 'margin-right', 'margin-top',
  50. 'max-height', 'max-width', 'min-height', 'min-width', 'opacity', 'orphans',
  51. 'outline', 'outline-color', 'outline-style', 'outline-width', 'overflow',
  52. 'padding', 'padding-bottom', 'padding-left', 'padding-right', 'padding-top',
  53. 'page-break-after', 'page-break-before', 'page-break-inside', 'pause',
  54. 'pause-after', 'pause-before', 'pitch', 'pitch-range', 'play-during',
  55. 'position', 'quotes', 'richness', 'right', 'speak', 'speak-header',
  56. 'speak-numeral', 'speak-punctuation', 'speech-rate', 'stress', 'table-layout',
  57. 'text-align', 'text-decoration', 'text-indent', 'text-shadow',
  58. 'text-transform', 'top', 'unicode-bidi', 'vertical', 'vertical-align',
  59. 'visibility', 'voice-family', 'volume', 'white-space', 'widows', 'width',
  60. 'word-spacing', 'z-index'
  61. }
  62. for i = 1, #properties do
  63. properties[i] = completion:format(properties[i], XPM.METHOD)
  64. end
  65. -- List of pseudoclasses available for autocompletion.
  66. local pseudoclasses = {
  67. 'active', 'first-child', 'focus', 'hover', 'lang', 'link', 'visited',
  68. }
  69. for i = 1, #pseudoclasses do
  70. pseudoclasses[i] = completion:format(pseudoclasses[i], XPM.SIGNAL)
  71. end
  72. -- List of pseudoelements available for autocompletion.
  73. local pseudoelements = {'after', 'before', 'first-letter', 'first-line'}
  74. for i = 1, #pseudoelements do
  75. pseudoelements[i] = completion:format(pseudoelements[i], XPM.SLOT)
  76. end
  77. -- List of media types available for autocompletion.
  78. local medias = {
  79. 'all', 'aural', 'braille', 'embossed', 'handheld', 'print', 'projection',
  80. 'screen', 'tty', 'tv'
  81. }
  82. for i = 1, #medias do medias[i] = completion:format(medias[i], XPM.TYPEDEF) end
  83. -- Map of properties to their value lists.
  84. -- Most of the properties that are commented out are defined later, and in terms
  85. -- of other properties. For example, "border" is defined in terms of
  86. -- "border-color", "border-style", and "border-width".
  87. local values = {
  88. azimuth = {
  89. 'left-side', 'far-left', 'left', 'center-left', 'center', 'center-right',
  90. 'right', 'far-right', 'right-side', 'behind', 'leftwards', 'rightwards'
  91. },
  92. --background =
  93. ['background-attachment'] = {'fixed', 'scroll'},
  94. ['background-color'] = {'transparent', 'rgb('},
  95. ['background-image'] = {'url(', 'none'},
  96. ['background-position'] = {'left', 'top', 'center', 'bottom', 'right'},
  97. ['background-repeat'] = {'repeat', 'repeat-x', 'repeat-y', 'no-repeat'},
  98. --border =
  99. --['border-bottom'] =
  100. --['border-bottom-color'] =
  101. --['border-bottom-style'] =
  102. --['border-bottom-width'] =
  103. ['border-collapse'] = {'collapse', 'separate'},
  104. ['border-color'] = {'transparent', 'rgb('},
  105. --['border-left'] =
  106. --['border-left-color'] =
  107. --['border-left-style'] =
  108. --['border-left-width'] =
  109. --['border-right'] =
  110. --['border-right-color'] =
  111. --['border-right-style'] =
  112. --['border-right-width'] =
  113. --['border-spacing'] = nil,
  114. ['border-style'] = {
  115. 'none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge',
  116. 'inset', 'outset'
  117. },
  118. --['border-top'] =
  119. --['border-top-color'] =
  120. --['border-top-style'] =
  121. --['border-top-width'] =
  122. ['border-width'] = {'thin', 'medium', 'thick'},
  123. bottom = {'auto'},
  124. ['caption-side'] = {'top', 'bottom'},
  125. clear = {'left', 'right', 'both', 'none'},
  126. clip = {'auto', 'rect('},
  127. color = {'rgb('},
  128. content = {
  129. 'none', 'normal', 'counter', 'attr(', 'open-quote', 'close-quote',
  130. 'no-open-quote', 'no-close-quote', 'url('
  131. },
  132. ['counter-increment'] = {'none'},
  133. ['counter-reset'] = {'none'},
  134. cue = {'none', 'url('},
  135. --['cue-after'] =
  136. --['cue-before'] =
  137. cursor = {
  138. 'url(', 'auto', 'crosshair', 'default', 'pointer', 'move', 'e-resize',
  139. 'ne-resize', 'nw-resize', 'n-resize', 'se-resize', 'sw-resize', 's-resize',
  140. 'w-resize', 'text', 'wait', 'help', 'progress'
  141. },
  142. direction = {'ltr', 'rtl'},
  143. display = {
  144. 'none', 'block', 'inline', 'inline-block', 'inline-table', 'list-item',
  145. 'run-in', 'table', 'table-caption', 'table-cell', 'table-column',
  146. 'table-column-group', 'table-footer-group', 'table-header-group',
  147. 'table-row', 'table-row-group'
  148. },
  149. elevation = {'below', 'level', 'above', 'higher', 'lower'},
  150. ['empty-cells'] = {'hide', 'show'},
  151. float = {'left', 'right', 'none'},
  152. font = { -- font-family, font-size, etc. added later
  153. 'caption', 'icon', 'menu', 'message-box', 'small-caption', 'status-bar'
  154. },
  155. ['font-family'] = {'sans-serif', 'serif', 'monospace', 'cursive', 'fantasy'},
  156. ['font-size'] = {
  157. 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large',
  158. 'smaller', 'larger'
  159. },
  160. ['font-size-adjust'] = {'none'},
  161. --['font-stretch'] = nil,
  162. ['font-style'] = {'normal', 'italic', 'oblique'},
  163. ['font-variant'] = {'normal', 'small-caps'},
  164. ['font-weight'] = {
  165. 'normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500',
  166. '600', '700', '800', '900',
  167. },
  168. height = {'auto'},
  169. left = {'auto'},
  170. ['letter-spacing'] = {'normal'},
  171. ['line-height'] = {'normal'},
  172. --['list-style'] = nil,
  173. ['list-style-image'] = {'url(', 'none'},
  174. ['list-style-position'] = {'inside', 'outside'},
  175. ['list-style-type'] = {
  176. 'none', 'disc', 'circle', 'square', 'decimal', 'decimal-leading-zero',
  177. 'armenian', 'georgian', 'lower-alpha', 'lower-greek', 'lower-latin',
  178. 'upper-latin', 'lower-roman', 'upper-roman'
  179. },
  180. margin = {'auto'},
  181. ['margin-bottom'] = {'auto'},
  182. ['margin-left'] = {'auto'},
  183. ['margin-right'] = {'auto'},
  184. ['margin-top'] = {'auto'},
  185. ['max-height'] = {'auto'},
  186. ['max-width'] = {'none'},
  187. ['min-height'] = {'none'},
  188. ['min-width'] = {'none'},
  189. --opacity = nil,
  190. --orphans = nil,
  191. --outline =
  192. ['outline-color'] = {'invert', 'rgb('},
  193. ['outline-style'] = {
  194. 'none', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset',
  195. 'outset'
  196. },
  197. ['outline-width'] = {'thin', 'medium', 'thick'},
  198. overflow = {'auto', 'hidden', 'scroll', 'visible'},
  199. --padding = nil,
  200. --['padding-bottom'] = nil,
  201. --['padding-left'] = nil,
  202. --['padding-right'] = nil,
  203. --['padding-top'] = nil,
  204. ['page-break-after'] = {'auto', 'always', 'avoid', 'left', 'right'},
  205. --['page-break-before'] =
  206. ['page-break-inside'] = {'auto', 'avoid'},
  207. --pause = nil,
  208. --['pause-after'] = nil,
  209. --['pause-before'] = nil,
  210. pitch = {'x-low', 'low', 'medium', 'high', 'x-high'},
  211. --['pitch-range'] = nil,
  212. ['play-during'] = {'url(', 'mix', 'repeat', 'auto', 'none'},
  213. position = {'absolute', 'fixed', 'relative', 'static'},
  214. quotes = {'none'},
  215. --richness = nil,
  216. right = {'auto'},
  217. speak = {'normal', 'none', 'spell-out'},
  218. ['speak-header'] = {'always', 'once'},
  219. ['speak-numeral'] = {'digits', 'continuous'},
  220. ['speak-punctuation'] = {'code', 'none'},
  221. ['speech-rate'] = {
  222. 'x-slow', 'slow', 'medium', 'fast', 'x-fast', 'faster', 'slower'
  223. },
  224. --stress = nil,
  225. ['table-layout'] = {'auto', 'fixed'},
  226. ['text-align'] = {'left', 'right', 'center', 'justify'},
  227. ['text-decoration'] = {
  228. 'none', 'underline', 'overline', 'line-through', 'blink'
  229. },
  230. --['text-indent'] = nil,
  231. ['text-shadow'] = {'none'},
  232. ['text-transform'] = {'none', 'capitalize', 'uppercase', 'lowercase'},
  233. top = {'auto'},
  234. ['unicode-bidi'] = {'normal', 'embed', 'bidi-override'},
  235. ['vertical-align'] = {
  236. 'baseline', 'sub', 'super', 'top', 'text-top', 'middle', 'bottom',
  237. 'text-bottom'
  238. },
  239. visibility = {'visible', 'hidden', 'collapse'},
  240. --['voice-family'] = nil,
  241. volume = {'silent', 'x-soft', 'soft', 'medium', 'loud', 'x-loud'},
  242. ['white-space'] = {'normal', 'pre', 'nowrap', 'pre-wrap', 'pre-line'},
  243. --widows = nil,
  244. width = {'auto'},
  245. ['word-spacing'] = {'normal'},
  246. ['z-index'] = {'auto'}
  247. }
  248. for _, values in pairs(values) do
  249. for i = 1, #values do
  250. values[i] = completion:format(values[i], XPM.VARIABLE)
  251. end
  252. end
  253. local initial = completion:format('initial', XPM.VARIABLE)
  254. local inherit = completion:format('inherit', XPM.VARIABLE)
  255. -- Define some properties in terms of others.
  256. values.background = {}
  257. for _, kind in ipairs{'attachment', 'color', 'image', 'position', 'repeat'} do
  258. values.background[#values.background + 1] = values['background-'..kind]
  259. end
  260. values.border = {
  261. values['border-color'], values['border-style'], values['border-width']
  262. }
  263. for _, direction in ipairs{'bottom', 'left', 'right', 'top'} do
  264. values['border-'..direction] = values.border
  265. values['border-'..direction..'-color'] = values['border-color']
  266. values['border-'..direction..'-style'] = values['border-style']
  267. values['border-'..direction..'-width'] = values['border-width']
  268. end
  269. values['cue-after'], values['cue-before'] = values.cue, values.cue
  270. for _, kind in ipairs{'family', 'size', 'style', 'variant', 'weight'} do
  271. values.font[#values.font + 1] = values['font-'..kind]
  272. end
  273. values.outline = {
  274. values['outline-color'], values['outline-style'], values['outline-width']
  275. }
  276. values['page-break-before'] = values['page-break-after']
  277. textadept.editing.autocompleters.css = function()
  278. local list = {}
  279. -- Retrieve the symbol behind the caret and determine whether it is a
  280. -- selector, property, media type, etc.
  281. local line, pos = buffer:get_cur_line()
  282. line = line:sub(1, pos)
  283. local symbol, op, part = line:match('([%w-]-)(:?:?)%s*([%w-]*)$')
  284. if symbol == '' and part == '' then return nil end -- nothing to complete
  285. local name = '^'..part
  286. local in_selector = line:find('{[^}]*$')
  287. local completions
  288. if not line:find('@media[^{]*$') then
  289. -- Autocomplete selector, pseudoclass, pseudoelement, property, or value,
  290. -- depending on context.
  291. if not in_selector then
  292. for i = buffer:line_from_position(buffer.current_pos) - 1, 0, -1 do
  293. local line = buffer:get_line(i)
  294. if line:find('{[^}]*$') then in_selector = true break end
  295. if line:find('}[^{]*$') then break end -- not in selector
  296. end
  297. end
  298. if not in_selector then
  299. if op == '' then
  300. completions = selectors -- autocomplete selector name
  301. elseif op == ':' then
  302. completions = pseudoclasses -- autocomplete pseudoclass
  303. else
  304. completions = pseudoelements -- autocomplete pseudoelement
  305. end
  306. else
  307. if symbol == '' then
  308. completions = properties -- autocomplete property
  309. elseif op == ':' then
  310. completions = values[symbol] -- autocomplete value.
  311. if not completions then return nil end
  312. else
  313. return nil
  314. end
  315. end
  316. else
  317. completions = medias -- autocomplete media type
  318. end
  319. -- Extract potential completions.
  320. for i = 1, #completions do
  321. local completion = completions[i]
  322. if type(completion) == 'string' then
  323. if completion:find(name) then list[#list + 1] = completion end
  324. else
  325. for j = 1, #completion do
  326. if completion[j]:find(name) then list[#list + 1] = completion[j] end
  327. end
  328. end
  329. end
  330. -- Include the omnipresent "initial" and "inherit" values, if applicable.
  331. if in_selector and symbol ~= '' then
  332. if initial:find(name) then list[#list + 1] = initial end
  333. if inherit:find(name) then list[#list + 1] = inherit end
  334. end
  335. return #part, list
  336. end
  337. textadept.editing.api_files.css = {
  338. _HOME..'/modules/css/api', _USERHOME..'/modules/css/api'
  339. }
  340. -- Commands.
  341. ---
  342. -- Container for CSS-specific key bindings.
  343. -- @class table
  344. -- @name _G.keys.css
  345. keys.css = {}
  346. -- Snippets.
  347. if type(snippets) == 'table' then
  348. ---
  349. -- Container for CSS-specific snippets.
  350. -- @class table
  351. -- @name _G.snippets.css
  352. snippets.css = {
  353. }
  354. end
  355. return M