Personal emacs config
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.

134 lines
4.2 KiB

  1. ;;; skewer-css.el --- skewer support for live-interaction CSS -*- lexical-binding: t; -*-
  2. ;; This is free and unencumbered software released into the public domain.
  3. ;;; Commentary:
  4. ;; This minor mode provides functionality for CSS like plain Skewer
  5. ;; does for JavaScript.
  6. ;; * C-x C-e -- `skewer-css-eval-current-declaration'
  7. ;; * C-M-x -- `skewer-css-eval-current-rule'
  8. ;; * C-c C-k -- `skewer-css-eval-buffer'
  9. ;; These functions assume there are no comments within a CSS rule,
  10. ;; *especially* not within a declaration. In the former case, if you
  11. ;; keep the comment free of CSS syntax it should be able to manage
  12. ;; reasonably well. This may be fixed someday.
  13. ;;; Code:
  14. (require 'css-mode)
  15. (require 'skewer-mode)
  16. (defun skewer-css-trim (string)
  17. "Trim and compress whitespace in the string."
  18. (let ((cleaned (replace-regexp-in-string "[\t\n ]+" " " string)))
  19. (replace-regexp-in-string "^[\t\n ]+\\|[\t\n ]+$" "" cleaned)))
  20. ;; Parsing
  21. (defun skewer-css-beginning-of-rule ()
  22. "Move to the beginning of the current rule and return point."
  23. (skewer-css-end-of-rule)
  24. (re-search-backward "{")
  25. (when (re-search-backward "[}/]" nil 'start)
  26. (forward-char))
  27. (re-search-forward "[^ \t\n]")
  28. (backward-char)
  29. (point))
  30. (defun skewer-css-end-of-rule ()
  31. "Move to the end of the current rule and return point."
  32. (if (eql (char-before) ?})
  33. (point)
  34. (re-search-forward "}")))
  35. (defun skewer-css-end-of-declaration ()
  36. "Move to the end of the current declaration and return point."
  37. (if (eql (char-before) ?\;)
  38. (point)
  39. (re-search-forward ";")))
  40. (defun skewer-css-beginning-of-declaration ()
  41. "Move to the end of the current declaration and return point."
  42. (skewer-css-end-of-declaration)
  43. (re-search-backward ":")
  44. (backward-sexp 1)
  45. (point))
  46. (defun skewer-css-selectors ()
  47. "Return the selectors for the current rule."
  48. (save-excursion
  49. (let ((start (skewer-css-beginning-of-rule))
  50. (end (1- (re-search-forward "{"))))
  51. (skewer-css-trim
  52. (buffer-substring-no-properties start end)))))
  53. (defun skewer-css-declaration ()
  54. "Return the current declaration as a pair of strings."
  55. (save-excursion
  56. (let ((start (skewer-css-beginning-of-declaration))
  57. (end (skewer-css-end-of-declaration)))
  58. (let* ((clip (buffer-substring-no-properties start end))
  59. (pair (split-string clip ":")))
  60. (mapcar #'skewer-css-trim pair)))))
  61. ;; Evaluation
  62. (defun skewer-css (rule)
  63. "Add RULE as a new stylesheet."
  64. (skewer-eval rule nil :type "css"))
  65. (defun skewer-css-eval-current-declaration ()
  66. "Evaluate the declaration at the point."
  67. (interactive)
  68. (save-excursion
  69. (let ((selectors (skewer-css-selectors))
  70. (rule (skewer-css-declaration))
  71. (start (skewer-css-beginning-of-declaration))
  72. (end (skewer-css-end-of-declaration)))
  73. (skewer-flash-region start end)
  74. (skewer-css (apply #'format "%s { %s: %s }" selectors rule)))))
  75. (defun skewer-css-eval-current-rule ()
  76. "Evaluate the rule at the point."
  77. (interactive)
  78. (save-excursion
  79. (let* ((start (skewer-css-beginning-of-rule))
  80. (end (skewer-css-end-of-rule))
  81. (rule (buffer-substring-no-properties start end)))
  82. (skewer-flash-region start end)
  83. (skewer-css (skewer-css-trim rule)))))
  84. (defun skewer-css-eval-buffer ()
  85. "Send the entire current buffer as a new stylesheet."
  86. (interactive)
  87. (skewer-css (buffer-substring-no-properties (point-min) (point-max))))
  88. (defun skewer-css-clear-all ()
  89. "Remove *all* Skewer-added styles from the document."
  90. (interactive)
  91. (skewer-eval nil nil :type "cssClearAll"))
  92. ;; Minor mode definition
  93. (defvar skewer-css-mode-map
  94. (let ((map (make-sparse-keymap)))
  95. (prog1 map
  96. (define-key map (kbd "C-x C-e") 'skewer-css-eval-current-declaration)
  97. (define-key map (kbd "C-M-x") 'skewer-css-eval-current-rule)
  98. (define-key map (kbd "C-c C-k") 'skewer-css-eval-buffer)
  99. (define-key map (kbd "C-c C-c") 'skewer-css-clear-all)))
  100. "Keymap for skewer-css-mode.")
  101. ;;;###autoload
  102. (define-minor-mode skewer-css-mode
  103. "Minor mode for interactively loading new CSS rules."
  104. :lighter " skewer-css"
  105. :keymap skewer-css-mode-map
  106. :group 'skewer)
  107. (provide 'skewer-css)
  108. ;;; skewer-css.el ends here