Repository: sharkdp/bat (language: rust)

Issue:
add ruby slim-lang syntax support
<!--
BEFORE YOU MAKE A REQUEST:

Are you looking to add a new syntax to use on one of your devices?
Bat supports locally-installed language definitions. See the link below:

https://github.com/sharkdp/bat#adding-new-syntaxes--language-definitions

If you think adding this syntax would help others as well, please make sure that it meets our
guidelines for adding new syntaxes:

 - 10,000 downloads on packagecontrol.io
-->


**Syntax:**
Ruby's slim templating language (`*.slim`)

**Guideline Criteria:**
https://packagecontrol.io/packages/Ruby%20Slim (67K downloads on packagecontrol.io)
https://github.com/slim-template/ruby-slim.tmbundle



Discussion / hints:

Fix patch:
diff --git a/.gitmodules b/.gitmodules
index f4bec7bd22..5f28570cf8 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -227,3 +227,6 @@
 [submodule "assets/syntaxes/02_Extra/LLVM"]
 	path = assets/syntaxes/02_Extra/LLVM
 	url = https://github.com/ioncodes/LLVM.tmBundle
+[submodule "assets/syntaxes/02_Extra/Slim"]
+	path = assets/syntaxes/02_Extra/Slim
+	url = https://github.com/slim-template/ruby-slim.tmbundle.git
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 707ea220d5..0460277062 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,7 +21,7 @@
 - LLVM, see #1777 (@ioncodes)
 - Highlight for `vimrc` and `gvimrc` files, see #1763 (@SuperSandro2000)
 - Syslog highlighting improvements, see #1793 (@scop)
-
+- Added support for `slim` syntax, see #1693 (@mfinelli)
 
 ## New themes
 
diff --git a/assets/syntaxes/02_Extra/Slim b/assets/syntaxes/02_Extra/Slim
new file mode 160000
index 0000000000..3b1441f89f
--- /dev/null
+++ b/assets/syntaxes/02_Extra/Slim
@@ -0,0 +1,1 @@
+Subproject commit 3b1441f89fde40678c3c0ada6d75ce46417a35b6
diff --git a/assets/syntaxes/02_Extra/Slim.sublime-syntax b/assets/syntaxes/02_Extra/Slim.sublime-syntax
new file mode 100644
index 0000000000..3d492aca95
--- /dev/null
+++ b/assets/syntaxes/02_Extra/Slim.sublime-syntax
@@ -0,0 +1,306 @@
+%YAML 1.2
+---
+# http://www.sublimetext.com/docs/syntax.html
+name: Ruby Slim
+file_extensions:
+  - slim
+  - skim
+scope: text.slim
+contexts:
+  main:
+    - match: ^(\s*)(ruby):$
+      captures:
+        2: constant.language.name.ruby.filter.slim
+      push:
+        - meta_scope: text.ruby.filter.slim
+        - match: ^(?!(\1\s)|\s*$)
+          pop: true
+        - include: scope:source.ruby
+    - match: ^(\s*)(javascript):$
+      captures:
+        2: constant.language.name.javascript.filter.slim
+      push:
+        - meta_scope: source.js.filter.slim
+        - match: ^(?!(\1\s)|\s*$)
+          pop: true
+        - include: scope:source.js
+    - match: ^(---)\s*\n
+      captures:
+        1: storage.frontmatter.slim
+      push:
+        - meta_scope: source.yaml.meta.slim
+        - match: ^(---)\s*\n
+          captures:
+            1: storage.frontmatter.slim
+          pop: true
+        - include: scope:source.yaml
+    - match: ^(\s*)(coffee):$
+      captures:
+        2: constant.language.name.coffeescript.filter.slim
+      push:
+        - meta_scope: text.coffeescript.filter.slim
+        - match: ^(?!(\1\s)|\s*$)
+          pop: true
+        - include: scope:source.coffee
+    - match: ^(\s*)(markdown):$
+      captures:
+        2: constant.language.name.markdown.filter.slim
+      push:
+        - meta_scope: text.markdown.filter.slim
+        - match: ^(?!(\1\s)|\s*$)
+          pop: true
+        - include: scope:text.html.markdown
+    - match: ^(\s*)(css):$
+      captures:
+        2: constant.language.name.css.filter.slim
+      push:
+        - meta_scope: text.css.filter.slim
+        - match: ^(?!(\1\s)|\s*$)
+          pop: true
+        - include: scope:source.css
+    - match: ^(\s*)(sass):$
+      captures:
+        2: constant.language.name.sass.filter.slim
+      push:
+        - meta_scope: text.sass.filter.slim
+        - match: ^(?!(\1\s)|\s*$)
+          pop: true
+        - include: scope:source.sass
+    - match: ^(\s*)(scss):$
+      captures:
+        2: constant.language.name.scss.filter.slim
+      push:
+        - meta_scope: text.scss.filter.slim
+        - match: ^(?!(\1\s)|\s*$)
+          pop: true
+        - include: scope:source.scss
+    - match: ^(\s*)(less):$
+      captures:
+        2: constant.language.name.less.filter.slim
+      push:
+        - meta_scope: text.less.filter.slim
+        - match: ^(?!(\1\s)|\s*$)
+          pop: true
+        - include: scope:source.less
+    - match: ^(\s*)(erb):$
+      captures:
+        2: constant.language.name.erb.filter.slim
+      push:
+        - meta_scope: text.erb.filter.slim
+        - match: ^(?!(\1\s)|\s*$)
+          pop: true
+        - include: scope:source.erb
+    - match: ^(! )($|\s.*)
+      scope: meta.prolog.slim
+      captures:
+        1: punctuation.definition.prolog.slim
+    - match: ^(\s*)(/)\s*.*$
+      captures:
+        2: comment.line.slash.slim
+      push:
+        - meta_scope: comment.block.slim
+        - match: ^(?!(\1\s)|\s*$)
+          pop: true
+    - match: ^\s*(?=-)
+      push:
+        - match: $
+          pop: true
+        - include: rubyline
+    - match: (?==+|~)
+      push:
+        - match: $
+          pop: true
+        - include: rubyline
+    - include: tag-attribute
+    - include: embedded-ruby
+    - match: ^(\s*)(\||')\s*
+      comment: Verbatim text (can include HTML tags and copied lines)
+      push:
+        - match: ^(?!(\1\s)|\s*$)
+          pop: true
+        - include: scope:text.html.basic
+        - include: embedded-ruby
+    - match: '^\s*(\.|#|[-a-zA-Z0-9]+)([\w-]+)?'
+      comment: '1 - dot OR hash OR any combination of word, number; 2 - OPTIONAL any combination of word, number, dash or underscore (following a . or'
+      captures:
+        1: entity.name.tag.slim
+        2: entity.other.attribute-name.event.slim
+      push:
+        - meta_scope: meta.tag
+        - match: '$|(?!\.|#|:|-|~|/|\}|\]|\*|\s?[\*\{])'
+          captures:
+            1: entity.name.tag.slim
+            2: entity.other.attribute-name.event.slim
+          pop: true
+        - match: '(:[\w\d]+)+'
+          comment: XML
+          push:
+            - meta_scope: entity.name.tag.slim
+            - match: $|\s
+              pop: true
+        - match: '(:\s)(\.|#|[a-zA-Z0-9]+)([\w-]+)?'
+          comment: Inline HTML / 1 - colon; 2 - dot OR hash OR any combination of word, number; 3 - OPTIONAL any combination of word, number, dash or underscore (following a . or
+          captures:
+            1: punctuation.definition.tag.end.slim
+            2: entity.name.tag.slim
+            3: entity.other.attribute-name.event.slim
+          push:
+            - match: '$|(?!\.|#|=|-|~|/|\}|\]|\*|\s?[\*\{])'
+              captures:
+                1: punctuation.definition.tag.end.slim
+                2: entity.name.tag.slim
+                3: entity.other.attribute-name.event.slim
+              pop: true
+            - include: root-class-id-tag
+            - include: tag-attribute
+        - match: '(\*\{)(?=.*\}|.*\|\s*$)'
+          comment: Splat attributes
+          captures:
+            1: punctuation.section.embedded.ruby
+          push:
+            - meta_scope: source.ruby.embedded.slim
+            - match: '(\})|$|^(?!.*\|\s*$)'
+              captures:
+                1: punctuation.section.embedded.ruby
+              pop: true
+            - include: embedded-ruby
+        - include: root-class-id-tag
+        - include: rubyline
+        - match: /
+          scope: punctuation.terminator.tag.slim
+    - match: ^\s*(\\.)
+      captures:
+        1: meta.escape.slim
+    - match: ^\s*(?=\||')
+      push:
+        - match: $
+          pop: true
+        - include: embedded-ruby
+        - include: scope:text.html.basic
+    - match: '(?=<[\w\d\:]+)'
+      comment: Inline and root-level HTML tags
+      push:
+        - match: $|\/\>
+          pop: true
+        - include: scope:text.html.basic
+  continuation:
+    - match: '([\\,])\s*\n'
+      captures:
+        1: punctuation.separator.continuation.slim
+  delimited-ruby-a:
+    - match: '=\('
+      push:
+        - meta_scope: source.ruby.embedded.slim
+        - match: \)(?=( \w|$))
+          pop: true
+        - include: scope:source.ruby.rails
+  delimited-ruby-b:
+    - match: '=\['
+      push:
+        - meta_scope: source.ruby.embedded.slim
+        - match: '\](?=( \w|$))'
+          pop: true
+        - include: scope:source.ruby.rails
+  delimited-ruby-c:
+    - match: '=\{'
+      push:
+        - meta_scope: source.ruby.embedded.slim
+        - match: '\}(?=( \w|$))'
+          pop: true
+        - include: scope:source.ruby.rails
+  embedded-ruby:
+    - match: '(?<!\\)#\{{1,2}'
+      captures:
+        0: punctuation.section.embedded.ruby
+      push:
+        - meta_scope: source.ruby.embedded.html
+        - match: '\}{1,2}'
+          captures:
+            0: punctuation.section.embedded.ruby
+          pop: true
+        - include: scope:source.ruby.rails
+  entities:
+    - match: '(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)'
+      scope: constant.character.entity.html
+      captures:
+        1: punctuation.definition.entity.html
+        3: punctuation.definition.entity.html
+    - match: '&'
+      scope: invalid.illegal.bad-ampersand.html
+  interpolated-ruby:
+    - match: '=(?=\b)'
+      push:
+        - meta_scope: source.ruby.embedded.html
+        - match: \s|\w$
+          pop: true
+  root-class-id-tag:
+    - match: '(\.|#)([\w\d\-]+)'
+      captures:
+        1: punctuation.separator.key-value.html
+        2: entity.other.attribute-name.html
+  rubyline:
+    - match: (==|=)(<>|><|<'|'<|<|>)?|-
+      comment: Hack to thwart Sublime's Ruby highlighter. It thinks do without a variable continues the next line (this can be muted with a / at the end of the line). For things like yields, do is unnecessary without an argument, so this hack will suffice
+      push:
+        - meta_scope: meta.line.ruby.slim
+        - meta_content_scope: source.ruby.embedded.slim
+        - match: (do\s*\n$)|(?<!\\|,|,\n|\\\n)$
+          captures:
+            1: keyword.control.start-block.ruby
+          pop: true
+        - match: '#.*$'
+          comment: Hack to let ruby comments work in this context properly
+          scope: comment.line.number-sign.ruby
+        - include: continuation
+        - include: scope:source.ruby.rails
+  string-double-quoted:
+    - match: (")(?=.*")
+      captures:
+        0: punctuation.definition.string.begin.html
+      push:
+        - meta_scope: string.quoted.double.html
+        - meta_content_scope: meta.toc-list.id.html
+        - match: '"'
+          captures:
+            0: punctuation.definition.string.end.html
+          pop: true
+        - include: embedded-ruby
+        - include: entities
+  string-single-quoted:
+    - match: (')(?=.*')
+      captures:
+        0: punctuation.definition.string.begin.html
+      push:
+        - meta_scope: string.quoted.single.html
+        - meta_content_scope: meta.toc-list.id.html
+        - match: "'"
+          captures:
+            0: punctuation.definition.string.end.html
+          pop: true
+        - include: embedded-ruby
+        - include: entities
+  tag-attribute:
+    - match: '([\w.#_-]+)(=)(?!\s)(true|false|nil)?(\s*\(|\{)?'
+      captures:
+        1: entity.other.attribute-name.event.slim
+        2: punctuation.separator.key-value.html
+        3: constant.language.slim
+      push:
+        - meta_scope: meta.attribute-with-value.slim
+        - match: '\}|\)|$'
+          captures:
+            1: entity.other.attribute-name.event.slim
+            2: punctuation.separator.key-value.html
+            3: constant.language.slim
+          pop: true
+        - include: tag-stuff
+        - include: string-double-quoted
+        - include: string-single-quoted
+  tag-stuff:
+    - include: tag-attribute
+    - include: interpolated-ruby
+    - include: delimited-ruby-a
+    - include: delimited-ruby-b
+    - include: delimited-ruby-c
+    - include: rubyline
+    - include: embedded-ruby


Test patch:
diff --git a/tests/syntax-tests/highlighted/Slim/test.slim b/tests/syntax-tests/highlighted/Slim/test.slim
new file mode 100644
index 0000000000..2a157a03ee
--- /dev/null
+++ b/tests/syntax-tests/highlighted/Slim/test.slim
@@ -0,0 +1,20 @@
+[38;2;249;38;114mdoctype[0m[38;2;248;248;242m html[0m
+[38;2;249;38;114mhtml[0m[38;2;248;248;242m [0m[38;2;166;226;46mlang[0m[38;2;166;226;46m=[0m[38;2;248;248;242mlocale[0m
+[38;2;248;248;242m  [0m[38;2;249;38;114mhead[0m
+[38;2;248;248;242m    [0m[38;2;249;38;114mmeta[0m[38;2;248;248;242m [0m[38;2;166;226;46mcharset[0m[38;2;166;226;46m=[0m[38;2;255;255;255m'[0m[38;2;230;219;116mutf-8[0m[38;2;255;255;255m'[0m
+[38;2;248;248;242m    [0m[38;2;249;38;114mtitle[0m[38;2;248;248;242m [0m[38;2;249;38;114m#{[0m[38;2;246;170;17m@[0m[38;2;255;255;255mtitle[0m[38;2;248;248;242m [0m[38;2;249;38;114m?[0m[38;2;248;248;242m [0m[38;2;249;38;114m"[0m[38;2;248;248;242m#{[0m[38;2;246;170;17m@[0m[38;2;255;255;255mtitle[0m[38;2;248;248;242m}[0m[38;2;230;219;116m | Testing[0m[38;2;249;38;114m"[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[38;2;249;38;114m'[0m[38;2;230;219;116mTesting[0m[38;2;249;38;114m'[0m[38;2;249;38;114m}[0m
+[38;2;248;248;242m    [0m[38;2;248;248;242m==[0m[38;2;248;248;242m stylesheet[0m[38;2;255;255;255m([0m[38;2;249;38;114m'[0m[38;2;230;219;116mapp.css[0m[38;2;249;38;114m'[0m[38;2;255;255;255m)[0m
+
+[38;2;248;248;242m  [0m[38;2;249;38;114mbody[0m
+[38;2;248;248;242m    [0m[38;2;249;38;114mheader[0m
+[38;2;248;248;242m      [0m[38;2;249;38;114mh1[0m[38;2;166;226;46m.[0m[38;2;166;226;46mtitle[0m[38;2;248;248;242m Testing[0m
+
+[38;2;248;248;242m      [0m[38;2;248;248;242m-[0m[38;2;248;248;242m [0m[38;2;246;170;17m@[0m[38;2;255;255;255mlinks[0m[38;2;248;248;242m.[0m[38;2;248;248;242meach [0m[38;2;249;38;114mdo[0m[38;2;248;248;242m [0m[38;2;248;248;242m|[0m[3;38;2;253;151;31mlink[0m[38;2;248;248;242m|[0m
+[38;2;248;248;242m        [0m[38;2;249;38;114ma[0m[38;2;248;248;242m [0m[38;2;166;226;46mhref[0m[38;2;166;226;46m=[0m[38;2;248;248;242mlink.href[0m
+[38;2;248;248;242m          [0m[38;2;248;248;242m=[0m[38;2;248;248;242mlink[0m[38;2;248;248;242m.[0m[38;2;248;248;242mtitle[0m
+[38;2;248;248;242m    [0m[38;2;249;38;114mdiv[0m
+[38;2;248;248;242m      [0m[38;2;248;248;242m==[0m[38;2;248;248;242m [0m[38;2;249;38;114myield[0m
+
+[38;2;248;248;242m    [0m[38;2;248;248;242m-[0m[38;2;248;248;242m [0m[38;2;249;38;114mif[0m[38;2;248;248;242m [0m[38;2;102;217;239mAPP_ENV[0m[38;2;248;248;242m [0m[38;2;249;38;114m==[0m[38;2;248;248;242m [0m[38;2;249;38;114m'[0m[38;2;230;219;116mproduction[0m[38;2;249;38;114m'[0m
+[38;2;248;248;242m      [0m[38;2;249;38;114mfooter[0m
+[38;2;248;248;242m        [0m[38;2;249;38;114mp[0m[38;2;248;248;242m Testing[0m
diff --git a/tests/syntax-tests/source/Slim/test.slim b/tests/syntax-tests/source/Slim/test.slim
new file mode 100644
index 0000000000..e52f70ddb7
--- /dev/null
+++ b/tests/syntax-tests/source/Slim/test.slim
@@ -0,0 +1,20 @@
+doctype html
+html lang=locale
+  head
+    meta charset='utf-8'
+    title #{@title ? "#{@title} | Testing" : 'Testing'}
+    == stylesheet('app.css')
+
+  body
+    header
+      h1.title Testing
+
+      - @links.each do |link|
+        a href=link.href
+          =link.title
+    div
+      == yield
+
+    - if APP_ENV == 'production'
+      footer
+        p Testing