2 Commits

9 changed files with 2105 additions and 13 deletions
Split View
  1. +14
    -13
      init.el
  2. +24
    -0
      scopes-mode/LICENSE
  3. +24
    -0
      scopes-mode/README.md
  4. +30
    -0
      scopes-mode/generator.sc
  5. +281
    -0
      scopes-mode/scopes-mode.el
  6. +24
    -0
      scopes-mode/scopes-std-symbols/LICENSE
  7. +11
    -0
      scopes-mode/scopes-std-symbols/README.md
  8. +201
    -0
      scopes-mode/scopes-std-symbols/symbols.sc
  9. +1496
    -0
      scopes-mode/scopes-symbols.el

+ 14
- 13
init.el View File

@@ -35,7 +35,7 @@

;; Font
(set-face-attribute 'default nil :height 105)
(set-face-attribute 'default nil :font "monospace")
(set-face-attribute 'default nil :font "Consolas")

;; Theme
(add-to-list 'custom-theme-load-path "~/.emacs.d/themes")
@@ -87,6 +87,18 @@
(define-key term-raw-map (kbd "C-x o") 'other-window)
(define-key term-raw-map (kbd "C-x p") 'prev-window))

;; ANSI escape codes in compilation from
;; http://endlessparentheses.com/ansi-colors-in-the-compilation-buffer-output.html
(use-package ansi-color
:config
(defun endless/colorize-compilation ()
"Colorize from `compilation-filter-start' to `point'."
(let ((inhibit-read-only t))
(ansi-color-apply-on-region
compilation-filter-start (point))))
(add-hook 'compilation-filter-hook
#'endless/colorize-compilation))

;; Ido
(use-package ido)
(use-package ido-completing-read+)
@@ -209,7 +221,7 @@
(tab-count (how-many "^\t" (point-min) (point-max))))
(if (> space-count tab-count) (setq indent-tabs-mode nil))
(if (> tab-count space-count) (setq indent-tabs-mode t))))
(setq-default indent-tabs-mode t)
(setq-default indent-tabs-mode nil)
(infer-indentation-style)
(define-key global-map (kbd "RET") 'newline-and-indent)

@@ -224,17 +236,6 @@
(add-hook 'after-init-hook 'global-company-mode)
(define-key global-map (kbd "<backtab>") 'company-complete))

;; Window switching
(defun prev-window()
"Other-window but with arg -1."
(interactive)
(other-window -1))
(define-key global-map (kbd "C-x o") 'other-window)
(define-key global-map (kbd "C-x p") 'prev-window)
(when (boundp 'term-raw-map)
(define-key term-raw-map (kbd "C-x o") 'other-window)
(define-key term-raw-map (kbd "C-x p") 'prev-window))

;; Compiling
(global-set-key [f6] 'recompile)



+ 24
- 0
scopes-mode/LICENSE View File

@@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

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 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.

For more information, please refer to <https://unlicense.org>

+ 24
- 0
scopes-mode/README.md View File

@@ -0,0 +1,24 @@
# scopes-mode
Emacs major mode for the [Scopes](http://scopes.rocks/) programming language.
Highlights all keywords and numbers, along with all symbols defined in
`core.sc` and the default modules.

## Usage
The plugin is partially generated by a scopes program (`generator.sc`). To generate a new
version launch in a shell:

`scopes generator.sc > scopes-symbols.el`

The elisp library itself is already set up to use that file so no further
actions are needed. A pre generated version is already included in the
repository for convenience, so generation is only necessary if it's out of date.

## Screenshots
![light theme](https://cdn.discordapp.com/attachments/329404808643608586/644291595944067072/unknown.png)
![dark theme](https://media.discordapp.net/attachments/329404808643608586/644292579835248705/unknown.png)

## Special thanks

- [@flatwhatson](https://github.com/flatwhatson) for the help with the comment highlighting regex.
- [@hlissner](https://github.com/hlissner) for general emacs help; The indentation routine was also written
while looking at the `pug-mode` package for reference.

+ 30
- 0
scopes-mode/generator.sc View File

@@ -0,0 +1,30 @@
# Usage: `scopes generator.sc > scopes-symbols.el'
symbols := (import .scopes-std-symbols.symbols)

# header
print
"""";;; scopes-symbols.el --- Auto generated symbols for Scopes syntax highlighting. -*- lexical-binding: t; -*-
;;; Commentary:
;; Lists all keywords and symbols to be matched exactly by font-locking.
;;; Code:

inline generate-keyword-list-binding (kind)
..
"(defvar scopes-symbols-"
kind as string
" '("
fold (str = "") for k v in (getattr symbols kind)
# indentation hardcoded, because lazy
.. str "\n " (tostring (v as string))
"))"

print (generate-keyword-list-binding 'keywords)
print (generate-keyword-list-binding 'functions)
print (generate-keyword-list-binding 'operators)
print (generate-keyword-list-binding 'types)
print (generate-keyword-list-binding 'sugar-macros)
print (generate-keyword-list-binding 'spice-macros)
print (generate-keyword-list-binding 'global-symbols)
print (generate-keyword-list-binding 'special-constants)

print ";;; scopes-symbols.el ends here"

+ 281
- 0
scopes-mode/scopes-mode.el View File

@@ -0,0 +1,281 @@
;;; scopes-mode.el --- Major mode for editing Scopes code. -*- coding: utf-8; lexical-binding: t; -*-

;; Copyright © 2019, by Westerbly (radgeRayden) Snaydley

;; Author: Westerbly Snaydley (westerbly@gmail.com)
;; Version: 0.1.0
;; Created: 2019-11-10
;; Keywords: languages

;; Homepage: https://github.com/radgeRayden/emacs-scopes-mode/

;; This file is not part of GNU Emacs.

;;; License:
;; This is free and unencumbered software released into the public domain.

;; Anyone is free to copy, modify, publish, use, compile, sell, or
;; distribute this software, either in source code form or as a compiled
;; binary, for any purpose, commercial or non-commercial, and by any
;; means.

;; In jurisdictions that recognize copyright laws, the author or authors
;; of this software dedicate any and all copyright interest in the
;; software to the public domain. We make this dedication for the benefit
;; of the public at large and to the detriment of our heirs and
;; successors. We intend this dedication to be an overt act of
;; relinquishment in perpetuity of all present and future rights to this
;; software under copyright law.

;; 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 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.

;; For more information, please refer to <https://unlicense.org>

;;; Commentary:

;; Major mode for the Scopes programming language. Know more at http://scopes.rocks/.

;;; Code:

;; Symbols are generated by generator.sc and stored in `scopes-symbols.el'.
(load-library "scopes-symbols.el")

;; Emacs doesn't highlight numbers by default; as such I didn't want to impose a standard face.
(defcustom scopes-number-font-face font-lock-constant-face
"Font face to use for number highlighting."
:type 'face
:group 'scopes)

(defvar scopes-font-lock-keywords
(let* (
(scopes-keywords-regexp (regexp-opt scopes-symbols-keywords 'symbols))
(scopes-functions-regexp (regexp-opt scopes-symbols-functions 'symbols))
(scopes-operators-regexp (regexp-opt scopes-symbols-operators 'symbols))
(scopes-types-regexp (regexp-opt scopes-symbols-types 'symbols))
(scopes-sugar-macros-regexp (regexp-opt scopes-symbols-sugar-macros 'symbols))
(scopes-spice-macros-regexp (regexp-opt scopes-symbols-spice-macros 'symbols))
(scopes-global-symbols-regexp (regexp-opt scopes-symbols-global-symbols 'symbols))
(scopes-special-constants-regexp (regexp-opt scopes-symbols-special-constants 'symbols)))
`(
;; block strings
(,(rx
(group-n 1 (* " ")) "\"\"\"\""
(* any) (or "\n" eol)
(*
(or
(: (* whitespace) "\n")
(group (backref 1) " " (* any) (or "\n" eol))))) . font-lock-string-face)
;; comments
(,(rx
(group-n 1 line-start (* " ")) "#" (* any) (or "\n" eol)
(*
(or
(: (* whitespace) (or "\n" eol))
(group (backref 1) " " (* any) (or "\n" eol))))) . font-lock-comment-face)
(,(rx "#" (* any) eol) . font-lock-comment-face)

;; it's less common for strings to contain comments, so I'm adding them last.
;; FIXME: use a parsing function instead of regexes, as every approach has been flawed somehow.
;; for example, here we can't highlight escapes inside strings without jumping through hoops, but could be done with a function.
;; inline strings
;; to make things easier, empty string is a special case.
(,(rx "\"\"") . font-lock-string-face)
(,(rx (: "\"" (+ (: (*? not-newline) (opt "\\\""))) "\"")) . font-lock-string-face)

;; number literals
(,(rx
symbol-start
(opt (any "+-"))
(or
(:
;; no fractional part
(or
;; decimal
(+ digit)
;; binary
(: "0b" (+ (any "01")))
;;octal
(: "0o" (+ (any "0-7")))
;;hex
(: "0x" (+ hex-digit)))
(opt (: ":" (or (: "f" (or "32" "64")) (: (any "ui") (or "8" "16" "32" "64")) "usize"))))
(:
;; floats with fractional part
(or
;; decimal prefix
(or (: (+ digit) ".") (: "." (+ digit)) (: (+ digit) "." (+ digit)))
;; binary prefix
(: "0b" (or (: (+ (any "01")) ".") (: "." (+ (any "01"))) (: (+ (any "01")) "." (+ (any "01")))))
;; octal prefix
(: "0o" (or (: (+ (any "0-7")) ".") (: "." (+ (any "0-7"))) (: (+ (any "0-7")) "." (+ (any "0-7")))))
;; hex prefix
(: "0x" (or (: (+ hex-digit) ".") (: "." (+ hex-digit)) (: (+ hex-digit) "." (+ hex-digit)))))
(opt (: "e" (any "+-") (+ digit)))
(opt (or ":f32" ":f64"))))
symbol-end) . scopes-number-font-face)

;; symbols and method calls
(,(rx (: "'" (+ (not (any ",()[]{} \n"))))) . font-lock-preprocessor-face)
(,scopes-functions-regexp . font-lock-function-name-face)
(,scopes-global-symbols-regexp . font-lock-variable-name-face)
(,scopes-spice-macros-regexp . font-lock-keyword-face)
(,scopes-sugar-macros-regexp . font-lock-builtin-face)
(,scopes-types-regexp . font-lock-type-face)
(,scopes-operators-regexp . font-lock-builtin-face)
(,scopes-special-constants-regexp . font-lock-constant-face)
(,scopes-keywords-regexp . font-lock-builtin-face))))

(defvar scopes-mode-syntax-table
(let ((table (make-syntax-table)))
(modify-syntax-entry ?@ "_" table)
(modify-syntax-entry ?| "_" table)
(modify-syntax-entry ?: "_" table)
(modify-syntax-entry ?. "_" table)
(modify-syntax-entry ?# "<" table)
(modify-syntax-entry ?\; "." table)
table))

(defvar scopes-new-code-block-regexp
(rx
(or
;; wish this could be generated! It requires manual cherry picking anyways.
;; of course for a few like `if' it would be useful to check if there isn't a multiline
;; parentheses going on, but I'll leave that to some other time.
(: line-start (* whitespace) (or "if"
"else"
"elseif"
"then"
"case"
"pass"
"default"
"except"
"fn"
"inline"
"label"
"do"
"embed"
"try"
"loop"
"for"
"fold"
"while"
"spice-quote"
"::"))
;; dangling equal sign
(: "=" (* " ") line-end))))

(defvar scopes-end-code-block-regexp
(rx (: line-start
(* whitespace)
(or
"return"
"break"
"repeat"
"continue"
"merge")
(or ";" (: (+ whitespace) (not whitespace))))))

(defun scopes-indent-line ()
"Indent code in multiples of four spaces.
Will align column to next multiple of four, up to previous line indentation + 4."
(interactive "*")
(let* ((prev-indent (save-excursion
(beginning-of-line)
(if (not (bobp))
(progn
(re-search-backward "[^ \n]" nil t)
(current-indentation))
0)))
(cur-indent (save-excursion (forward-to-indentation 0)))
(blank-line-p (save-excursion (beginning-of-line) (looking-at "[[:space:]]*$")))
(column-before-indent (current-column)))
;;is this the first line? just indent everything to 0.
(if (save-excursion (beginning-of-line) (bobp))
(indent-line-to 0)
(let* ((next-align (+ cur-indent (- 4 (% cur-indent 4))))
(aligned-p (save-excursion
(forward-to-indentation 0)
(= (current-column) next-align)))
(max-indent (+ prev-indent 4))
(closest-lower-indent
(let
((lower-than-prev (- prev-indent 4)))
(if (>= lower-than-prev 0)
lower-than-prev
0))))
;; are we indenting an already written line?
(if (not blank-line-p)
;; then we don't assume intention, and understand that the user might want to indent
;; to anywhere between where the text currently is and previous line indentation
;; + 4.
;; are we past indentation limit?
(if (>= cur-indent max-indent)
(indent-line-to max-indent)
;; add a level if we're already aligned, or align it.
(if aligned-p
(indent-line-to (+ cur-indent 4))
(indent-line-to next-align)))

;; are we on an entirely new line?
(if (= column-before-indent 0)
;; Check if new block or continue previous block.
(let* ((prev-line-end-point (save-excursion
(forward-line -1)
(end-of-line)
(point)))
(new-block-p (save-excursion
(forward-line -1)
(beginning-of-line)
(re-search-forward scopes-new-code-block-regexp prev-line-end-point t)))
(end-block-p (save-excursion
(forward-line -1)
(beginning-of-line)
(re-search-forward scopes-end-code-block-regexp prev-line-end-point t))))
(cond
(new-block-p (indent-line-to max-indent))
(end-block-p (indent-line-to closest-lower-indent))
(t (progn (indent-line-to prev-indent)))))

;; otherwise, align or indent forward.
(if (>= cur-indent max-indent)
(indent-line-to max-indent)
;; add a level if we're already aligned, or align it.
(if aligned-p
(indent-line-to (+ cur-indent 4))
(indent-line-to next-align))))))))
(if (< (current-column) (current-indentation))
(forward-to-indentation 0)))

;;;autoload
(define-derived-mode scopes-mode scheme-mode "Scopes"
"Major mode for editing Scopes code."

(set-syntax-table scopes-mode-syntax-table)
(setq-local comment-start "#")
(setq-local comment-start-skip "#+ *")
(setq-local comment-end "")
(setq-local comment-add 0)
(setq-local comment-use-syntax nil)
(setq-local electric-indent-inhibit t)
;; TODO: change to a custom indent function that behaves differently inside a
;; parenthesized expression
(setq-local indent-line-function 'scopes-indent-line)
(electric-indent-local-mode -1)
;; (setq-)
(setq font-lock-multiline t
font-lock-defaults '((scopes-font-lock-keywords) t)))

;;;###autoload
(add-to-list 'auto-mode-alist '("\\.sc\\'" . scopes-mode))

;; add the mode to the `features' list
(provide 'scopes-mode)

;;; scopes-mode.el ends here

+ 24
- 0
scopes-mode/scopes-std-symbols/LICENSE View File

@@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

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 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.

For more information, please refer to <https://unlicense.org>

+ 11
- 0
scopes-mode/scopes-std-symbols/README.md View File

@@ -0,0 +1,11 @@
# scopes-std-symbols
Small Scopes module that exports all "standard" symbols categorized, for the consumption of plugin generators.

## Usage:
Import this module into your generator and iterate on all subscopes, outputting
keyword definitions.
Most keys are named after their values, but where that wasn't possible (constants) `_` was
preprended; the values on the other hand have the exact representation necessary
to match for syntax highlighting, so you should iterate on those. All values are strings.

An example of a generator can be found in https://github.com/radgeRayden/emacs-scopes-mode.

+ 201
- 0
scopes-mode/scopes-std-symbols/symbols.sc View File

@@ -0,0 +1,201 @@
# usage: import the module and interate on the VALUES in each subscope.
let standard-lib =
..
globals;
import Array
import Box
import Capture
import console
import enum
import FunctionChain
import glm
import glsl
import itertools
import Map
import spicetools
import struct
import testing
import UTF-8
import property
import Option

let styles-map =
do
let style-none = "None"
let style-symbol = "Symbol"
let style-string = "String"
let style-keyword = 'keywords
let style-function = 'functions
let style-sfxfunction = 'functions
let style-operator = 'operators
let style-instruction = "Instruction"
let style-type = 'types
let style-comment = "Comment"
let style-error = "Error"
let style-warning = "Warning"
let style-location = "Location"
locals;

let symbols =
do
let
# here we prepopulate some symbols that won't come up with the automatic query.
keywords =
'bind-symbols (Scope)
else = "else"
elseif = "elseif"
then = "then"
case = "case"
pass = "pass"
default = "default"
curly-list = "curly-list"
quote = "quote"
unquote-splice = "unquote-splice"
syntax-log = "syntax-log"
in = "in"
square-list = "square-list"
options = "options"
static = "static"
plain = "plain"
packed = "packed"
new = "new"
continue = "continue"
except = "except"
define-infix = "define-infix"
this-function = "this-function"
: = ":"
functions = (Scope)
operators =
'bind-symbols (Scope)
-> = "->"
** = "**"
// = "//"
>> = ">>"
<< = "<<"
//= = "//="
//= = "//="
>>= = ">>="
<<= = "<<="
| = "|"
|| = "||"

types =
'bind-symbols (Scope)
this-type = "this-type"
super-type = "super-type"
sugar-macros = (Scope)
spice-macros = (Scope)
global-symbols =
'bind-symbols (Scope)
main-module? = "main-module?"
module-dir = "module-dir"
module-path = "module-path"
module-name = "module-name"
special-constants =
'bind-symbols (Scope)
true = "true"
false = "false"
null = "null"
none = "none"
unnamed = "unnamed"
pi = "pi"
pi:f32 = "pi:f32"
pi:f64 = "pi:f64"
e = "e"
e:f32 = "e:f32"
e:f64 = "e:f64"
_+inf = "+inf"
_-inf = "-inf"
_nan = "nan"
_Inf = "Inf"
_-Inf = "-Inf"
_NaN = "NaN"
modules =
'bind-symbols (Scope)
Array = "Array"
Box = "Box"
Capture = "Capture"
console = "console"
enum = "enum"
FunctionChain = "FunctionChain"
glm = "glm"
glsl = "glsl"
itertools = "itertools"
Map = "Map"
spicetools = "spicetools"
struct = "struct"
testing = "testing"
UTF-8 = "UTF-8"
property = "property"
Option = "Option"
locals;
run-stage;

inline merge-scopes (scopes...)
va-lfold (Scope)
inline (__discard arg result)
fold (result = result) for k v in arg
'bind result k v
scopes...
let blacklist =
merge-scopes
symbols.keywords
symbols.functions
symbols.operators
symbols.types
symbols.sugar-macros
symbols.spice-macros
symbols.global-symbols
symbols.special-constants
run-stage;

let symbols =
fold (superscope = symbols) for scope in ('lineage standard-lib)
fold (superscope = superscope) for k v in scope
inline add-symbol (subscope-sym k)
let subscope = (('@ superscope subscope-sym) as Scope)
let subscope = ('bind subscope k (k as string))
'bind superscope subscope-sym subscope

let _type = ('typeof v)
k as:= Symbol
name := (k as string)
let style = (sc_symbol_style k)

inline has-key? (scope k)
try
('@ scope k)
true
except (ex)
false
if (has-key? blacklist k)
# skip key entirely
superscope
elseif (style != 'style-symbol)
let subscope-sym = ('@ styles-map style)
add-symbol subscope-sym k
# fallback for symbols not defined in cpp-land
elseif (_type == Unknown)
# some Closures get type "Unknown" for some reason
(as? ('@ scope k) Closure) and (add-symbol 'functions k) or superscope
# external scopes functions
elseif (or
(va@ 0 ('match? "^sc_" name))
# in some cases the only way to detect an extern
(('superof ('typeof v)) == pointer))
add-symbol 'functions k
elseif (_type == Closure)
add-symbol 'functions k
elseif (_type == type)
add-symbol 'types k
elseif (_type == SugarMacro)
add-symbol 'sugar-macros k
elseif (_type == SpiceMacro)
add-symbol 'spice-macros k
elseif (_type == Generator)
add-symbol 'functions k
elseif ((k as string) == "")
#edge case
add-symbol 'global-symbols "#unnamed"
else
add-symbol 'global-symbols k

+ 1496
- 0
scopes-mode/scopes-symbols.el
File diff suppressed because it is too large
View File


Loading…
Cancel
Save