-
-
Notifications
You must be signed in to change notification settings - Fork 526
Editing Ledger files with Sublime Text or RubyMine
This is a plugin to do syntax highlighting for Ledger files on the Sublime Text editor. It is a TextMate-style syntax file so it should work on all editors that understand that: TextMate, Sublime Text and RubyMine all work.
These files are written in XML, but it's easier to write them in YAML as described on this page and use a plugin to translate them to XML.
If you don't want to modify the plugin then you can just download the compiled XML and save it as Ledger.tmLanguage, drop it into the Packages/User directory and then restart the editor. On my Mac, that directory is located here: ~/Library/Application Support/Sublime Text 3/Packages/User. If you want to make changes to the plugin then you can find the YAML from which the plugin is generated below.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>fileTypes</key>
<array>
<string>ldg</string>
<string>ledger</string>
<string>ldgr</string>
</array>
<key>name</key>
<string>Ledger</string>
<key>patterns</key>
<array>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>comment.line</string>
</dict>
</dict>
<key>match</key>
<string>^(([;#|*%]).*)$</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>string.other.date</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>punctuation.separator</string>
</dict>
<key>3</key>
<dict>
<key>name</key>
<string>string.other.edate</string>
</dict>
<key>4</key>
<dict>
<key>name</key>
<string>constant.other</string>
</dict>
<key>5</key>
<dict>
<key>name</key>
<string>comment</string>
</dict>
<key>6</key>
<dict>
<key>name</key>
<string>markup.quote</string>
</dict>
<key>7</key>
<dict>
<key>name</key>
<string>comment</string>
</dict>
</dict>
<key>match</key>
<string>^(\d{4}[/-]\d{2}[/-]\d{2})(=)?(\d{4}[/-]\d{2}[/-]\d{2})?(\s+[*!])?(\s+\([^)]+\))?\s+([^;]+)((?:\t|\s\s);.*)?$</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>keyword.other</string>
</dict>
</dict>
<key>match</key>
<string>^\s+(note|alias|payee|check|assert|eval|default)(?:\s.*)?$</string>
</dict>
<dict>
<key>begin</key>
<string>^\s+([()\[\]\w\:\s_-]+)\s+(=\s*)?([^;@]+)?(\s*@[^;]+)?</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>markup.bold.account</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>markup.heading</string>
</dict>
<key>3</key>
<dict>
<key>name</key>
<string>variable.other.amount</string>
</dict>
<key>4</key>
<dict>
<key>name</key>
<string>markup.quote</string>
</dict>
</dict>
<key>end</key>
<string>$</string>
<key>patterns</key>
<array>
<dict>
<key>begin</key>
<string>(?<=\s\s|\t);[^:]*</string>
<key>end</key>
<string>$</string>
<key>name</key>
<string>comment</string>
<key>patterns</key>
<array>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>string.other</string>
</dict>
</dict>
<key>comment</key>
<string>tag</string>
<key>match</key>
<string>(:(?:[^ :]+:)+)</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>string.other</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>markup.quote</string>
</dict>
</dict>
<key>comment</key>
<string>metadata</string>
<key>match</key>
<string>(\w+::?)\s+(.*)</string>
</dict>
</array>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>^(?:\s\s+|\t)(;)</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>comment</string>
</dict>
</dict>
<key>end</key>
<string>$</string>
<key>patterns</key>
<array>
<dict>
<key>begin</key>
<string></string>
<key>end</key>
<string>$</string>
<key>name</key>
<string>comment</string>
<key>patterns</key>
<array>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>string.other</string>
</dict>
</dict>
<key>comment</key>
<string>tag</string>
<key>match</key>
<string>(:(?:[^ :]+:)+)</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>string.other</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>markup.quote</string>
</dict>
</dict>
<key>comment</key>
<string>metadata</string>
<key>match</key>
<string>(\w+::?)\s+(.*)</string>
</dict>
</array>
</dict>
</array>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>keyword.control</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>string.other.date</string>
</dict>
<key>3</key>
<dict>
<key>name</key>
<string>variable.other.amount</string>
</dict>
<key>4</key>
<dict>
<key>name</key>
<string>markup.quote</string>
</dict>
<key>5</key>
<dict>
<key>name</key>
<string>comment</string>
</dict>
</dict>
<key>match</key>
<string>^(P)\s+(\d{4}[/-]\d{2}[/-]\d{2}(?:\s\d\d:\d\d:\d\d)?)\s+(\w+)\s([^;]+)((?:\s\s|\t);.*)?$</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>keyword.other</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>string.regexp.expression</string>
</dict>
<key>3</key>
<dict>
<key>name</key>
<string>comment</string>
</dict>
</dict>
<key>match</key>
<string>^(~|=)\s(.*?)((?:\s\s|\t);.*)?$</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>keyword.other</string>
</dict>
</dict>
<key>match</key>
<string>^([a-z]+|[A-Z]).*$</string>
</dict>
</array>
<key>scopeName</key>
<string>source.ledger</string>
<key>uuid</key>
<string>806052d8-c579-43e0-918e-02ba9033b149</string>
</dict>
</plist>Here's the YAML source, you only need that if you want to improve it and compile it yourself:
# [PackageDev] target_format: plist, ext: tmLanguage
---
name: Ledger
scopeName: source.ledger
uuid: 806052d8-c579-43e0-918e-02ba9033b149
fileTypes:
- ldg
- ledger
- ldgr
patterns:
- captures:
'1':
name: comment.line
match: "^(([;#|*%]).*)$"
- captures:
'1':
name: string.other.date
'2':
name: punctuation.separator
'3':
name: string.other.edate
'4':
name: constant.other
'5':
name: comment
'6':
name: markup.quote
'7':
name: comment
match: "^(\\d{4}[/-]\\d{2}[/-]\\d{2})(=)?(\\d{4}[/-]\\d{2}[/-]\\d{2})?(\\s+[*!])?(\\s+\\([^)]+\\))?\\s+([^;]+)((?:\\t|\\s\\s);.*)?$"
- captures:
'1':
name: keyword.other
match: "^\\s+(note|alias|payee|check|assert|eval|default)(?:\\s.*)?$"
- begin: "^\\s+([()\\[\\]\\w\\:\\s_-]+)\\s+(=\\s*)?([^;@]+)?(\\s*@[^;]+)?"
beginCaptures:
'1':
name: markup.bold.account
'2':
name: markup.heading
'3':
name: variable.other.amount
'4':
name: markup.quote
end: "$"
patterns:
- begin: "(?<=\\s\\s|\\t);[^:]*"
# begin should be "(?<=\\s\\s|\\t);" but RubyMine does not play nice
end: "$"
name: comment
patterns:
- captures:
'1':
name: string.other
comment: tag
match: "(:(?:[^ :]+:)+)"
- captures:
'1':
name: string.other
'2':
name: markup.quote
comment: metadata
match: "(\\w+::?)\\s+(.*)"
- begin: "^(?:\\s\\s+|\\t)(;)"
beginCaptures:
'1':
name: comment
end: "$"
patterns:
- begin: ""
end: "$"
name: comment
patterns:
- captures:
'1':
name: string.other
comment: tag
match: "(:(?:[^ :]+:)+)"
- captures:
'1':
name: string.other
'2':
name: markup.quote
comment: metadata
match: "(\\w+::?)\\s+(.*)"
- captures:
'1':
name: keyword.control
'2':
name: string.other.date
'3':
name: variable.other.amount
'4':
name: markup.quote
'5':
name: comment
match: "^(P)\\s+(\\d{4}[/-]\\d{2}[/-]\\d{2}(?:\\s\\d\\d:\\d\\d:\\d\\d)?)\\s+(\\w+)\\s([^;]+)((?:\\s\\s|\\t);.*)?$"
- captures:
'1':
name: keyword.other
'2':
name: string.regexp.expression
'3':
name: comment
match: "^(~|=)\\s(.*?)((?:\\s\\s|\\t);.*)?$"
- captures:
'1':
name: keyword.other
match: "^([a-z]+|[A-Z]).*$"