├── .python-version
├── tests
├── __init__.py
├── test_json.py
└── validate_json_format.py
├── .gitignore
├── docs
├── src
│ ├── markdown
│ │ ├── _snippets
│ │ │ ├── refs.md
│ │ │ ├── abbr.md
│ │ │ └── links.md
│ │ ├── images
│ │ │ └── Example.png
│ │ ├── index.md
│ │ ├── about
│ │ │ ├── license.md
│ │ │ └── contributing.md
│ │ ├── installation.md
│ │ └── usage.md
│ ├── requirements.txt
│ └── dictionary
│ │ └── en-custom.txt
└── theme
│ └── announce.html
├── messages.json
├── dependencies.json
├── messages
├── install.md
└── rencent.md
├── Default.sublime-commands
├── raw_line_edit.sublime-settings
├── tox.ini
├── .github
├── labels.yml
└── workflows
│ ├── deploy.yml
│ └── build.yml
├── Default.sublime-keymap
├── README.md
├── CHANGES.md
├── Main.sublime-menu
├── .pyspelling.yml
├── mkdocs.yml
├── support.py
└── raw_line_edit.py
/.python-version:
--------------------------------------------------------------------------------
1 | 3.13
2 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | """Unit Tests."""
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | site/*
2 | *.pyc
3 | build/*
4 | .tox/*
5 |
--------------------------------------------------------------------------------
/docs/src/markdown/_snippets/refs.md:
--------------------------------------------------------------------------------
1 | --8<--
2 | links.md
3 | abbr.md
4 | --8<--
5 |
--------------------------------------------------------------------------------
/docs/src/markdown/_snippets/abbr.md:
--------------------------------------------------------------------------------
1 | *[ST2]: Sublime Text 2
2 | *[ST3]: Sublime Text 3
3 |
--------------------------------------------------------------------------------
/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "install": "messages/install.md",
3 | "2.1.0": "messages/recent.md"
4 | }
5 |
--------------------------------------------------------------------------------
/dependencies.json:
--------------------------------------------------------------------------------
1 | {
2 | "*": {
3 | ">=4201": [
4 | "mdpopups"
5 | ]
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/docs/src/markdown/images/Example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/facelessuser/RawLineEdit/HEAD/docs/src/markdown/images/Example.png
--------------------------------------------------------------------------------
/docs/src/requirements.txt:
--------------------------------------------------------------------------------
1 | mkdocs_pymdownx_material_extras>=1.2.2
2 | mkdocs-git-revision-date-localized-plugin
3 | mkdocs-minify-plugin
4 | pyspelling
5 |
--------------------------------------------------------------------------------
/messages/install.md:
--------------------------------------------------------------------------------
1 | # RawLineEdit
2 |
3 | Welcome to RawLineEdit! Check out the documentation:
4 | `Preferences->Package Settings->RawLineEdit->Documentation`.
5 |
--------------------------------------------------------------------------------
/messages/rencent.md:
--------------------------------------------------------------------------------
1 | # RawLineEdit
2 |
3 | New release!
4 |
5 | Please see `Preferences->Package Settings->RawLineEdit->Changelog`
6 | for more info about the release.
7 |
8 | ## 2.1.0
9 |
10 | - **NEW**: Updates for Python 3.13 on ST 4201+.
11 |
--------------------------------------------------------------------------------
/docs/src/dictionary/en-custom.txt:
--------------------------------------------------------------------------------
1 | Changelog
2 | Cmd
3 | Ctrl
4 | JSON
5 | MERCHANTABILITY
6 | MkDocs
7 | NONINFRINGEMENT
8 | PyMdown
9 | RawLineEdit
10 | SubNotify
11 | Twemoji
12 | changelog
13 | glyphs
14 | installable
15 | keybinding
16 | macOS
17 | requesters
18 | sublicense
19 | tmTheme
20 |
--------------------------------------------------------------------------------
/docs/src/markdown/index.md:
--------------------------------------------------------------------------------
1 | # RawLineEdit
2 |
3 | ## Overview
4 |
5 | 
6 |
7 | View and edit line endings in Sublime Text. RawLineEdit displays line endings very clearly and allows changing the line
8 | endings per line (something sublime text doesn't allow out of the box).
9 |
--------------------------------------------------------------------------------
/docs/src/markdown/_snippets/links.md:
--------------------------------------------------------------------------------
1 | [mkdocs]: http://www.mkdocs.org
2 | [mkdocs-material]: https://github.com/squidfunk/mkdocs-material
3 | [package-control]: https://packagecontrol.io/
4 | [package-control-install]: https://packagecontrol.io/installation
5 | [pymdown-extensions]: https://github.com/facelessuser/pymdown-extensions
6 | [subnotify]: https://github.com/facelessuser/SubNotify
7 |
--------------------------------------------------------------------------------
/docs/theme/announce.html:
--------------------------------------------------------------------------------
1 |
2 | {% set icon = "material/alert-decagram" %}
3 | {% include ".icons/" ~ icon ~ ".svg" %}
4 |
5 | Sponsorship
6 | is now available!
7 |
8 | {% set icon = "octicons/heart-fill-16" %}
9 | {% include ".icons/" ~ icon ~ ".svg" %}
10 |
11 |
--------------------------------------------------------------------------------
/Default.sublime-commands:
--------------------------------------------------------------------------------
1 | [
2 | //////////////////////////////////
3 | // Raw Line Edit
4 | //////////////////////////////////
5 | {
6 | "caption": "Raw Line Edit: Toggle Line Edit Mode",
7 | "command": "toggle_raw_line_edit"
8 | },
9 | {
10 | "caption": "Raw Line Edit: View Line Endings",
11 | "command": "popup_raw_line_edit"
12 | }
13 | ]
14 |
--------------------------------------------------------------------------------
/raw_line_edit.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // Use subnotify if available
3 | "use_sub_notify": true,
4 |
5 | // Operate on sublime unsaved view buffer
6 | // Instead of reading the file from disk,
7 | // The file will be read directly from the buffer
8 | // In these cases the line endings will be normalized,
9 | // but you can edit them and save them back to disk.
10 | // Not sure how useful this is.
11 | "operate_on_unsaved_buffers": false
12 | }
13 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | skipsdist=True
3 | envlist =
4 | py39,py310,py311,py312,py313,py314,lint
5 |
6 | [testenv]
7 | deps=
8 | pytest
9 | commands=
10 | py.test .
11 |
12 | [testenv:documents]
13 | deps=
14 | -rdocs/src/requirements.txt
15 | commands=
16 | "{envpython}" -m mkdocs build --clean --verbose --strict
17 | pyspelling
18 |
19 | [testenv:lint]
20 | deps=
21 | flake8
22 | flake8_docstrings
23 | pep8-naming
24 | flake8-mutable
25 | flake8-builtins
26 | commands=
27 | flake8 "{toxinidir}"
28 |
29 | [flake8]
30 | ignore=D202,D203,D401,W504
31 | max-line-length=120
32 | exclude=site/*.py,.tox/*
33 |
--------------------------------------------------------------------------------
/.github/labels.yml:
--------------------------------------------------------------------------------
1 | template: 'facelessuser:master-labels:labels.yml:master'
2 |
3 | # Wildcard labels
4 |
5 | brace_expansion: true
6 | extended_glob: true
7 | minus_negate: false
8 |
9 | rules:
10 | - labels: ['C: infrastructure']
11 | patterns: ['*|!@(*.md|*.py|*.sublime-@(keymap|menu|settings|commands))', '.github/**']
12 |
13 | - labels: ['C: source']
14 | patterns: ['**/@(*.py|*.sublime-@(keymap|menu|settings|commands))|!tests']
15 |
16 | - labels: ['C: docs']
17 | patterns: ['**/*.md|docs/**']
18 |
19 | - labels: ['C: tests']
20 | patterns: ['tests/**']
21 |
22 | - labels: ['C: settings']
23 | patterns: ['*.sublime-@(keymap|menu|settings|commands)']
24 |
25 | # Label management
26 |
27 | labels:
28 | - name: 'C: settings'
29 | renamed: settings
30 | color: subcategory
31 | description: Related to Sublime settings.
32 |
--------------------------------------------------------------------------------
/Default.sublime-keymap:
--------------------------------------------------------------------------------
1 | [
2 | //////////////////////////////////
3 | // Raw Line Edit
4 | //////////////////////////////////
5 | {
6 | "keys": ["enter"],
7 | "command": "raw_line_insert",
8 | "context":
9 | [
10 | {
11 | "key": "raw_line_edit"
12 | }
13 | ],
14 | "args": { "style": "Unix" }
15 | },
16 | {
17 | "keys": ["shift+enter"],
18 | "command": "raw_line_insert",
19 | "context":
20 | [
21 | {
22 | "key": "raw_line_edit"
23 | }
24 | ],
25 | "args": { "style": "Windows" }
26 | },
27 | {
28 | "keys": ["ctrl+enter"],
29 | "command": "raw_line_insert",
30 | "context":
31 | [
32 | {
33 | "key": "raw_line_edit"
34 | }
35 | ],
36 | "args": { "style": "MacOS" }
37 | }
38 | ]
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [![Donate via PayPal][donate-image]][donate-link]
2 | [![Package Control Downloads][pc-image]][pc-link]
3 | ![License][license-image]
4 | # RawLineEdit
5 |
6 | 
7 |
8 | View and edit line endings in Sublime Text. RawLineEdit displays line endings very clearly and allows changing the line
9 | endings per line (something sublime text doesn't allow out of the box).
10 |
11 | # Documentation
12 |
13 | http://facelessuser.github.io/RawLineEdit/
14 |
15 | # License
16 |
17 | Raw Line Edit is released under the MIT license.
18 |
19 | [pc-image]: https://img.shields.io/packagecontrol/dt/RawLineEdit.svg?logo=sublime%20text&logoColor=cccccc
20 | [pc-link]: https://packagecontrol.io/packages/RawLineEdit
21 | [license-image]: https://img.shields.io/badge/license-MIT-blue.svg
22 | [donate-image]: https://img.shields.io/badge/Donate-PayPal-3fabd1?logo=paypal
23 | [donate-link]: https://www.paypal.me/facelessuser
24 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: deploy
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'st3-*'
7 | - 'st4-*'
8 |
9 | jobs:
10 |
11 | documents:
12 |
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v4
17 | with:
18 | fetch-depth: 0
19 | - name: Set up Python
20 | uses: actions/setup-python@v4
21 | with:
22 | python-version: 3.11
23 | - name: Install dependencies
24 | run: |
25 | python -m pip install --upgrade pip setuptools build
26 | python -m pip install -r docs/src/requirements.txt
27 | - name: Deploy documents
28 | run: |
29 | git config user.name facelessuser
30 | git config user.email "${{ secrets.GH_EMAIL }}"
31 | git remote add gh-token "https://${{ secrets.GH_TOKEN }}@github.com/facelessuser/RawLineEdit.git"
32 | git fetch gh-token && git fetch gh-token gh-pages:gh-pages
33 | python -m mkdocs gh-deploy -v --clean --remote-name gh-token
34 | git push gh-token gh-pages
35 |
--------------------------------------------------------------------------------
/docs/src/markdown/about/license.md:
--------------------------------------------------------------------------------
1 | # License
2 |
3 | Raw Line Edit is released under the MIT license.
4 |
5 | Copyright (c) 2013 - 2025 Isaac Muse
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
8 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
9 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
10 | persons to whom the Software is furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
13 | Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
16 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 |
--------------------------------------------------------------------------------
/tests/test_json.py:
--------------------------------------------------------------------------------
1 | """Test JSON."""
2 | import unittest
3 | from . import validate_json_format
4 | import os
5 | import fnmatch
6 |
7 |
8 | class TestSettings(unittest.TestCase):
9 | """Test JSON settings."""
10 |
11 | def _get_json_files(self, pattern, folder='.'):
12 | """Get JSON files."""
13 |
14 | for root, dirnames, filenames in os.walk(folder):
15 | for filename in fnmatch.filter(filenames, pattern):
16 | yield os.path.join(root, filename)
17 | dirnames = [d for d in dirnames if d not in ('.svn', '.git', '.tox')]
18 |
19 | def test_json_settings(self):
20 | """Test each JSON file."""
21 |
22 | patterns = (
23 | '*.sublime-settings',
24 | '*.sublime-keymap',
25 | '*.sublime-commands',
26 | '*.sublime-menu',
27 | '*.sublime-theme',
28 | '*.sublime-color-scheme'
29 | )
30 |
31 | for pattern in patterns:
32 | for f in self._get_json_files(pattern):
33 | self.assertFalse(
34 | validate_json_format.CheckJsonFormat(False, True).check_format(f),
35 | "%s does not comform to expected format!" % f
36 | )
37 |
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 | # RawLineEdit
2 |
3 | ## 2.1.0
4 |
5 | - **NEW**: Updates for Python 3.13 on ST 4201+.
6 |
7 | ## 2.0.3
8 |
9 | - **FIX**: Update dependencies to remove unnecessary ones and add `typing`.
10 |
11 | ## 2.0.2
12 |
13 | - **FIX**: Fix issue when viewing a file over and over old phantoms persist.
14 |
15 | ## 2.0.1
16 |
17 | - **FIX**: Fix installation message referring to non-existent quick start guide.
18 |
19 | ## 2.0.0
20 |
21 | - **NEW**: When view is unsaved, allow the ability to save, continue without saving, and canceling when using popup
22 | output.
23 | - **NEW**: Raw Line views will now use phantoms to show line endings.
24 | - **NEW**: Raw Line views will always use the same syntax as the original view.
25 | - **NEW**: Raw Line views, due to change in implementation (phantoms), can now properly handle toggling between macOS
26 | 9 `\r`, Windows `\r\n`, and Linux/Unix `\n` line endings.
27 | - **NEW**: Remove `view_only` setting as you can now call either the edit command or the view command as desired.
28 |
29 | ## 1.2.1
30 |
31 | - **FIX**: When view is unsaved, allow the ability to save, continue without saving, and canceling.
32 |
33 | ## 1.2.0
34 |
35 | - **FIX**: Update dependencies.
36 |
37 | ## 1.1.0
38 |
39 | - **NEW**: Migrate to tag releases.
40 |
41 | ## 1.0.0
42 |
43 | - **NEW**: Initial release.
44 |
--------------------------------------------------------------------------------
/docs/src/markdown/installation.md:
--------------------------------------------------------------------------------
1 | # Installation
2 |
3 | ## Package Control
4 |
5 | The recommended way to install RawLineEdit is via [Package Control][package-control]. Package Control will install the
6 | correct branch on your system and keep it up to date.
7 |
8 | 1. Ensure Package Control is installed. Instructions are found [here][package-control-install].
9 |
10 | 2. In Sublime Text, press ++ctrl+shift+p++ (Win, Linux) or ++cmd+shift+p++ (macOS) to bring up the quick panel and
11 | start typing `Package Control: Install Package`. Select the command and it will show a list of installable plugins.
12 |
13 | 3. Start typing `RawLineEdit`; when you see it, select it.
14 |
15 | 4. Restart to be sure everything is loaded proper.
16 |
17 | 5. Enjoy!
18 |
19 | ## Git Cloning
20 |
21 | /// warning | Warning
22 | This is not the recommended way to install RawLineEdit for the casual user as it requires the user to know which
23 | branch to install, know how to use git, and **will not** get automatically updated.
24 |
25 | If you are forking for a pull request, this is the way to go, just replace the official repository with the link for
26 | your fork.
27 | ///
28 |
29 | 1. Quit Sublime Text.
30 |
31 | 2. Open a terminal:
32 |
33 | ```
34 | cd /path/to/Sublime Text 3/Packages
35 | git clone https://github.com/facelessuser/RawLineEdit.git RawLineEdit
36 | ```
37 |
38 | 3. Restart Sublime Text.
39 |
40 | --8<-- "refs.md"
41 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on:
4 | push:
5 | branches:
6 | - 'master'
7 | tags:
8 | - '**'
9 | pull_request:
10 | branches:
11 | - '**'
12 |
13 | jobs:
14 | tests:
15 |
16 | env:
17 | TOXENV: py311
18 |
19 | runs-on: ubuntu-latest
20 |
21 | steps:
22 | - uses: actions/checkout@v4
23 | - name: Set up Python
24 | uses: actions/setup-python@v4
25 | with:
26 | python-version: 3.11
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip setuptools tox build
30 | - name: Tests
31 | run: |
32 | python -m tox
33 |
34 | lint:
35 |
36 | env:
37 | TOXENV: lint
38 |
39 | runs-on: ubuntu-latest
40 |
41 | steps:
42 | - uses: actions/checkout@v4
43 | - name: Set up Python
44 | uses: actions/setup-python@v4
45 | with:
46 | python-version: 3.11
47 | - name: Install dependencies
48 | run: |
49 | python -m pip install --upgrade pip setuptools tox build
50 | - name: Lint
51 | run: |
52 | python -m tox
53 |
54 | documents:
55 |
56 | env:
57 | TOXENV: documents
58 |
59 | runs-on: ubuntu-latest
60 |
61 | steps:
62 | - uses: actions/checkout@v4
63 | - name: Set up Python
64 | uses: actions/setup-python@v4
65 | with:
66 | python-version: 3.11
67 | - name: Install dependencies
68 | run: |
69 | python -m pip install --upgrade pip setuptools tox build
70 | - name: Install Aspell
71 | run: |
72 | sudo apt-get install aspell aspell-en
73 | - name: Build documents
74 | run: |
75 | python -m tox
76 |
--------------------------------------------------------------------------------
/docs/src/markdown/usage.md:
--------------------------------------------------------------------------------
1 | # User Guide
2 |
3 | ## General Usage
4 |
5 | Toggle the current view to a "RawLineEdit" view via the command palette command `Raw Line Edit: Toggle Line Edit Mode`.
6 | To simply view the raw line endings in a output panel, call the command `Raw Line Edit: View Line Endings`.
7 |
8 | Using the ++enter++ key you can change a line ending to Windows style, to Linux/Unix style with ++shift+enter++, or even
9 | macOS 9 with ++ctrl+enter++. Select multiple lines to change more than one line.
10 |
11 | ## Settings
12 |
13 | RawLineEdit has a few settings that can tweak the behavior and look of the plugin.
14 |
15 | ### `operate_on_unsaved_buffers`
16 |
17 | Allows RawLineEdit to operate on views that haven't been saved to disk.
18 |
19 | ```js
20 | // Operate on sublime unsaved view buffer
21 | // Instead of reading the file from disk,
22 | // The file will be read directly from the buffer
23 | // In these cases the line endings will be normalized,
24 | // but you can edit them and save them back to disk.
25 | // Not sure how useful this is.
26 | "operate_on_unsaved_buffers": false
27 | ```
28 |
29 | ### `use_sub_notify`
30 |
31 | Enables sending messages through the [SubNotify][subnotify] plugin.
32 |
33 | ```javascript
34 | // Use subnotify if available
35 | "use_sub_notify": true,
36 | ```
37 |
38 | ## Create Key Bindings
39 |
40 | To enable raw line edit/view mode via a keybinding you can bind the following commands:
41 |
42 | - `toggle_raw_line_edit`: a command for create a view where you can view and modify line endings.
43 | - `popup_raw_line_edit`: creates an output panel with a read only view of the line endings.
44 |
45 | --8<-- "refs.md"
46 |
--------------------------------------------------------------------------------
/Main.sublime-menu:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "caption": "Preferences",
4 | "mnemonic": "n",
5 | "id": "preferences",
6 | "children":
7 | [
8 | {
9 | "caption": "Package Settings",
10 | "mnemonic": "P",
11 | "id": "package-settings",
12 | "children":
13 | [
14 | {
15 | "caption": "RawLineEdit",
16 | "children":
17 | [
18 | {
19 | "command": "edit_settings", "args": {
20 | "base_file": "${packages}/RawLineEdit/raw_line_edit.sublime-settings",
21 | "default": "{\n$0\n}\n"
22 | },
23 | "caption": "Settings"
24 | },
25 | { "caption": "-" },
26 | {
27 | "caption": "Changelog",
28 | "command": "raw_line_edit_changes"
29 | },
30 | {
31 | "caption": "Documentation",
32 | "command": "export_html_open_site",
33 | "args": {
34 | "url": "http://facelessuser.github.io/RawLineEdit/"
35 | }
36 | },
37 | { "caption": "-" },
38 | {
39 | "caption": "Support Info",
40 | "command": "raw_line_edit_support_info"
41 | },
42 | {
43 | "caption": "Issues",
44 | "command": "raw_line_edit_open_site",
45 | "args": {
46 | "url": "https://github.com/facelessuser/RawLineEdit/issues"
47 | }
48 | },
49 | { "caption": "-" }
50 | ]
51 | }
52 | ]
53 | }
54 | ]
55 | }
56 | ]
57 |
--------------------------------------------------------------------------------
/.pyspelling.yml:
--------------------------------------------------------------------------------
1 | matrix:
2 | - name: settings
3 | sources:
4 | - '**/*.sublime-settings'
5 | aspell:
6 | lang: en
7 | dictionary:
8 | wordlists:
9 | - docs/src/dictionary/en-custom.txt
10 | output: build/dictionary/settings.dic
11 | pipeline:
12 | - pyspelling.filters.cpp:
13 | prefix: 'st'
14 | group_comments: true
15 | line_comments: false
16 | - pyspelling.filters.context:
17 | context_visible_first: true
18 | escapes: '\\[\\`]'
19 | delimiters:
20 | # Ignore multiline content between fences (fences can have 3 or more back ticks)
21 | # ```
22 | # content
23 | # ```
24 | - open: '(?s)^(?P *`{3,})$'
25 | close: '^(?P=open)$'
26 | # Ignore text between inline back ticks
27 | - open: '(?P`+)'
28 | close: '(?P=open)'
29 | - pyspelling.filters.url:
30 |
31 | - name: mkdocs
32 | sources:
33 | - site/**/*.html
34 | aspell:
35 | lang: en
36 | dictionary:
37 | wordlists:
38 | - docs/src/dictionary/en-custom.txt
39 | output: build/dictionary/mkdocs.dic
40 | pipeline:
41 | - pyspelling.filters.html:
42 | comments: false
43 | attributes:
44 | - title
45 | - alt
46 | ignores:
47 | - 'code, pre, a.magiclink, span.keys'
48 | - '.MathJax_Preview, .md-nav__link, .md-footer-custom-text, .md-source__repository, .headerlink, .md-icon'
49 | - '.md-social__link'
50 | - pyspelling.filters.url:
51 |
52 | - name: markdown
53 | sources:
54 | - README.md
55 | aspell:
56 | lang: en
57 | dictionary:
58 | wordlists:
59 | - docs/src/dictionary/en-custom.txt
60 | output: build/dictionary/markdown.dic
61 | pipeline:
62 | - pyspelling.filters.markdown:
63 | - pyspelling.filters.html:
64 | comments: false
65 | attributes:
66 | - title
67 | - alt
68 | ignores:
69 | - :is(code, pre)
70 | - pyspelling.filters.url:
71 |
72 | - name: python
73 | sources:
74 | - '*.py|tests/**/*.py'
75 | aspell:
76 | lang: en
77 | dictionary:
78 | wordlists:
79 | - docs/src/dictionary/en-custom.txt
80 | output: build/dictionary/python.dic
81 | pipeline:
82 | - pyspelling.filters.python:
83 | group_comments: true
84 | - pyspelling.flow_control.wildcard:
85 | allow:
86 | - py-comment
87 | - pyspelling.filters.context:
88 | context_visible_first: true
89 | delimiters:
90 | # Ignore lint (noqa) and coverage (pragma) as well as shebang (#!)
91 | - open: '^(?: *(?:noqa\b|pragma: no cover)|!)'
92 | close: '$'
93 | # Ignore Python encoding string -*- encoding stuff -*-
94 | - open: '^ *-\*-'
95 | close: '-\*-$'
96 | - pyspelling.filters.context:
97 | context_visible_first: true
98 | escapes: '\\[\\`]'
99 | delimiters:
100 | # Ignore multiline content between fences (fences can have 3 or more back ticks)
101 | # ```
102 | # content
103 | # ```
104 | - open: '(?s)^(?P *`{3,})$'
105 | close: '^(?P=open)$'
106 | # Ignore text between inline back ticks
107 | - open: '(?P`+)'
108 | close: '(?P=open)'
109 | - pyspelling.filters.url:
110 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: RawLineEdit Documentation
2 | site_url: https://facelessuser.github.io/RawLineEdit
3 | repo_url: https://github.com/facelessuser/RawLineEdit
4 | edit_uri: tree/master/docs/src/markdown
5 | site_description: View and edit raw lines in Sublime Text.
6 | copyright: |
7 | Copyright © 2013 - 2025 Isaac Muse
8 |
9 | docs_dir: docs/src/markdown
10 | theme:
11 | name: material
12 | custom_dir: docs/theme
13 | icon:
14 | logo: material/book-open-page-variant
15 | palette:
16 | scheme: dracula
17 | primary: deep purple
18 | accent: deep purple
19 | font:
20 | text: Roboto
21 | code: Roboto Mono
22 | features:
23 | - navigation.tabs
24 | - navigation.top
25 | - search.share
26 | - search.highlight
27 | - search.suggest
28 | pymdownx:
29 | sponsor: "https://github.com/sponsors/facelessuser"
30 |
31 | nav:
32 | - Home:
33 | - RawLineEdit: index.md
34 | - Installation: installation.md
35 | - User Guide: usage.md
36 | - About:
37 | - Contributing & Support: about/contributing.md
38 | - Changelog: https://github.com/facelessuser/RawLineEdit/blob/master/CHANGES.md
39 | - License: about/license.md
40 |
41 | markdown_extensions:
42 | - markdown.extensions.toc:
43 | slugify: !!python/name:pymdownx.slugs.uslugify
44 | permalink: ""
45 | - markdown.extensions.smarty:
46 | smart_quotes: false
47 | - pymdownx.betterem:
48 | - markdown.extensions.attr_list:
49 | - markdown.extensions.tables:
50 | - markdown.extensions.abbr:
51 | - markdown.extensions.footnotes:
52 | - markdown.extensions.md_in_html:
53 | - pymdownx.superfences:
54 | - pymdownx.highlight:
55 | extend_pygments_lang:
56 | - name: pycon3
57 | lang: pycon
58 | options:
59 | python3: true
60 | - pymdownx.inlinehilite:
61 | - pymdownx.magiclink:
62 | repo_url_shortener: true
63 | repo_url_shorthand: true
64 | social_url_shorthand: true
65 | user: facelessuser
66 | repo: RawLineEdit
67 | - pymdownx.tilde:
68 | - pymdownx.caret:
69 | - pymdownx.smartsymbols:
70 | - pymdownx.emoji:
71 | emoji_index: !!python/name:material.extensions.emoji.twemoji
72 | emoji_generator: !!python/name:material.extensions.emoji.to_svg
73 | - pymdownx.escapeall:
74 | hardbreak: true
75 | nbsp: true
76 | - pymdownx.tasklist:
77 | custom_checkbox: true
78 | - pymdownx.arithmatex:
79 | - pymdownx.mark:
80 | - pymdownx.striphtml:
81 | - pymdownx.snippets:
82 | base_path: docs/src/markdown/_snippets
83 | - pymdownx.keys:
84 | separator: "\uff0b"
85 | - pymdownx.saneheaders:
86 | - pymdownx.blocks.admonition:
87 | types:
88 | - new
89 | - settings
90 | - note
91 | - abstract
92 | - info
93 | - tip
94 | - success
95 | - question
96 | - warning
97 | - failure
98 | - danger
99 | - bug
100 | - example
101 | - quote
102 | - pymdownx.blocks.details:
103 | types:
104 | - name: details-new
105 | class: new
106 | - name: details-settings
107 | class: settings
108 | - name: details-note
109 | class: note
110 | - name: details-abstract
111 | class: abstract
112 | - name: details-info
113 | class: info
114 | - name: details-tip
115 | class: tip
116 | - name: details-success
117 | class: success
118 | - name: details-question
119 | class: question
120 | - name: details-warning
121 | class: warning
122 | - name: details-failure
123 | class: failure
124 | - name: details-danger
125 | class: danger
126 | - name: details-bug
127 | class: bug
128 | - name: details-example
129 | class: example
130 | - name: details-quote
131 | class: quote
132 | - pymdownx.blocks.html:
133 | - pymdownx.blocks.definition:
134 | - pymdownx.blocks.tab:
135 | alternate_style: True
136 |
137 | extra:
138 | social:
139 | - icon: fontawesome/brands/github
140 | link: https://github.com/facelessuser
141 |
142 | plugins:
143 | - search
144 | - git-revision-date-localized
145 | - mkdocs_pymdownx_material_extras
146 | - minify:
147 | minify_html: true
148 |
--------------------------------------------------------------------------------
/docs/src/markdown/about/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing & Support
2 |
3 | ## Overview
4 |
5 | Sublime Versions | Description
6 | ---------------- | -----------
7 | ST3 | Fully supported and actively maintained.
8 |
9 | Contribution from the community is encouraged and can be done in a variety of ways:
10 |
11 | - Become a sponsor.
12 | - Bug reports.
13 | - Reviewing code.
14 | - Code patches via pull requests.
15 | - Documentation improvements via pull requests.
16 |
17 | ## Bug Reports
18 |
19 | 1. Please **read the documentation** and **search the issue tracker** to try to find the answer to your question
20 | **before** posting an issue.
21 |
22 | 2. When creating an issue on the repository, please provide as much info as possible:
23 |
24 | - Provide environment information by running `Preferences->Package Settings->RawLineEdit->Support Info`. The
25 | information will be copied to the clipboard; paste the info in issue.
26 | - Errors in console.
27 | - Detailed description of the problem.
28 | - Examples for reproducing the error. You can post pictures, but if specific text or code is required to
29 | reproduce the issue, please provide the text in a plain text format for easy copy/paste.
30 |
31 | The more info provided, the greater the chance someone will take the time to answer, implement, or fix the issue.
32 |
33 | 3. Be prepared to answer questions and provide additional information if required. Issues in which the creator refuses
34 | to respond to follow up questions will be marked as stale and closed.
35 |
36 | ## Become a Sponsor :octicons-heart-fill-16:{: .heart-throb}
37 |
38 | Open source projects take time and money. Help support the project by becoming a sponsor. You can add your support at
39 | any tier you feel comfortable with. No amount is too little. We also accept one time contributions via PayPal.
40 |
41 | [:octicons-mark-github-16: GitHub Sponsors](https://github.com/sponsors/facelessuser){: .md-button .md-button--primary }
42 | [:fontawesome-brands-paypal: PayPal](https://www.paypal.me/facelessuser){ .md-button}
43 |
44 | ## Reviewing Code
45 |
46 | Take part in reviewing pull requests and/or reviewing direct commits. Make suggestions to improve the code and discuss
47 | solutions to overcome weakness in the algorithm.
48 |
49 | ## Pull Requests
50 |
51 | Pull requests are welcome, and if you plan on contributing directly to the code, there are a couple of things to be
52 | mindful of.
53 |
54 | Continuous integration tests on are run on all pull requests and commits via Travis CI. When making a pull request, the
55 | tests will automatically be run, and the request must pass to be accepted. You can (and should) run these tests before
56 | pull requesting. If it is not possible to run these tests locally, they will be run when the pull request is made, but
57 | it is strongly suggested that requesters make an effort to verify before requesting to allow for a quick, smooth merge.
58 |
59 | Feel free to use a virtual environment if you are concerned about installing any of the Python packages.
60 |
61 | ### Running Validation Tests
62 |
63 | /// tip | Tip
64 | If you are running Sublime on a macOS or Linux/Unix system, you run all tests by by running the shell script
65 | (assuming you have installed your environment fulfills all requirements below):
66 |
67 | ```
68 | chmod +x run_tests.sh
69 | ./run_tests.sh
70 | ```
71 | ///
72 |
73 | There are a couple of dependencies that must be present before running the tests.
74 |
75 | 1. As ST3 is the only current, actively supported version, Python 3.3 must be used to validate the tests.
76 |
77 | 2. Unit tests are run with `pytest`. You can install `pytest` via:
78 |
79 | ```
80 | pip install pytest
81 | ```
82 |
83 | The tests should be run from the root folder of the plugin by using the following command:
84 |
85 | ```
86 | py.test .
87 | ```
88 |
89 | 3. Linting is performed on the entire project with `flake8` with the plugins listed below:
90 |
91 | ```
92 | pip install flake8
93 | pip install flake8-docstrings
94 | pip install flake8-mutable
95 | pip install flake8-builtins
96 | pip install pep8-naming
97 | ```
98 |
99 | Linting is performed with the following command:
100 |
101 | ```
102 | flake8 .
103 | ```
104 |
105 | ## Documentation Improvements
106 |
107 | A ton of time has been spent not only creating and supporting this plugin, but also spent making this documentation. If
108 | you feel it is still lacking, show your appreciation for the plugin by helping to improve the documentation. Help with
109 | documentation is always appreciated and can be done via pull requests. There shouldn't be any need to run validation
110 | tests if only updating documentation.
111 |
112 | You don't have to render the docs locally before pull requesting, but if you wish to, I currently use a combination of
113 | [MkDocs][mkdocs], the [Material theme][mkdocs-material], and [PyMdown Extensions][pymdown-extensions] to render the
114 | docs. You can preview the docs if you install these two packages. The command for previewing the docs is
115 | `mkdocs serve` from the root directory. You can then view the documents at `localhost:8000`.
116 |
117 | --8<-- "refs.md"
118 |
--------------------------------------------------------------------------------
/support.py:
--------------------------------------------------------------------------------
1 | """Support command."""
2 | import sublime
3 | import sublime_plugin
4 | import textwrap
5 | import webbrowser
6 | import re
7 |
8 | __version__ = "2.1.0"
9 | __pc_name__ = 'RawLineEdit'
10 |
11 | CSS = '''
12 | div.raw-line-edit { padding: 10px; margin: 0; }
13 | .raw-line-edit h1, .raw-line-edit h2, .raw-line-edit h3,
14 | .raw-line-edit h4, .raw-line-edit h5, .raw-line-edit h6 {
15 | {{'.string'|css}}
16 | }
17 | .raw-line-edit blockquote { {{'.comment'|css}} }
18 | .raw-line-edit a { text-decoration: none; }
19 | '''
20 |
21 |
22 | def list2string(obj):
23 | """Convert list to string."""
24 |
25 | return '.'.join([str(x) for x in obj])
26 |
27 |
28 | def format_version(module, attr, call=False):
29 | """Format the version."""
30 |
31 | try:
32 | if call:
33 | version = getattr(module, attr)()
34 | else:
35 | version = getattr(module, attr)
36 | except Exception as e:
37 | print(e)
38 | version = 'Version could not be acquired!'
39 |
40 | if not isinstance(version, str):
41 | version = list2string(version)
42 | return version
43 |
44 |
45 | def is_installed_by_package_control():
46 | """Check if installed by package control."""
47 |
48 | settings = sublime.load_settings('Package Control.sublime-settings')
49 | return str(__pc_name__ in set(settings.get('installed_packages', [])))
50 |
51 |
52 | class RawLineEditSupportInfoCommand(sublime_plugin.ApplicationCommand):
53 | """Support info."""
54 |
55 | def run(self):
56 | """Run command."""
57 |
58 | info = {}
59 |
60 | info["platform"] = sublime.platform()
61 | info["version"] = sublime.version()
62 | info["arch"] = sublime.arch()
63 | info["plugin_version"] = __version__
64 | info["pc_install"] = is_installed_by_package_control()
65 | try:
66 | import mdpopups
67 | info["mdpopups_version"] = format_version(mdpopups, 'version', call=True)
68 | except Exception:
69 | info["mdpopups_version"] = 'Version could not be acquired!'
70 |
71 | msg = textwrap.dedent(
72 | """\
73 | - ST ver.: %(version)s
74 | - Platform: %(platform)s
75 | - Arch: %(arch)s
76 | - Plugin ver.: %(plugin_version)s
77 | - Install via PC: %(pc_install)s
78 | - mdpopups ver.: %(mdpopups_version)s
79 | """ % info
80 | )
81 |
82 | sublime.message_dialog(msg + '\nInfo has been copied to the clipboard.')
83 | sublime.set_clipboard(msg)
84 |
85 |
86 | class RawLineEditOpenSiteCommand(sublime_plugin.ApplicationCommand):
87 | """Open site links."""
88 |
89 | def run(self, url):
90 | """Open the URL."""
91 |
92 | webbrowser.open_new_tab(url)
93 |
94 |
95 | class RawLineEditDocCommand(sublime_plugin.WindowCommand):
96 | """Open doc page."""
97 |
98 | re_pkgs = re.compile(r'^Packages')
99 |
100 | def on_navigate(self, href):
101 | """Handle links."""
102 |
103 | if href.startswith('sub://Packages'):
104 | sublime.run_command('open_file', {"file": self.re_pkgs.sub('${packages}', href[6:])})
105 | else:
106 | webbrowser.open_new_tab(href)
107 |
108 | def run(self, page):
109 | """Open page."""
110 |
111 | try:
112 | import mdpopups
113 | has_phantom_support = (mdpopups.version() >= (1, 10, 0)) and (int(sublime.version()) >= 3124)
114 | except Exception:
115 | has_phantom_support = False
116 |
117 | if not has_phantom_support:
118 | sublime.run_command('open_file', {"file": page})
119 | else:
120 | text = sublime.load_resource(page.replace('${packages}', 'Packages'))
121 | view = self.window.new_file()
122 | view.set_name('RawLineEdit - Quick Start')
123 | view.settings().set('gutter', False)
124 | view.settings().set('word_wrap', False)
125 | if has_phantom_support:
126 | mdpopups.add_phantom(
127 | view,
128 | 'quickstart',
129 | sublime.Region(0),
130 | text,
131 | sublime.LAYOUT_INLINE,
132 | css=CSS,
133 | wrapper_class="raw-line-edit",
134 | on_navigate=self.on_navigate
135 | )
136 | else:
137 | view.run_command('insert', {"characters": text})
138 | view.set_read_only(True)
139 | view.set_scratch(True)
140 |
141 |
142 | class RawLineEditChangesCommand(sublime_plugin.WindowCommand):
143 | """Changelog command."""
144 |
145 | def run(self):
146 | """Show the changelog in a new view."""
147 | try:
148 | import mdpopups
149 | has_phantom_support = (mdpopups.version() >= (1, 10, 0)) and (int(sublime.version()) >= 3124)
150 | except Exception:
151 | has_phantom_support = False
152 |
153 | text = sublime.load_resource('Packages/RawLineEdit/CHANGES.md')
154 | view = self.window.new_file()
155 | view.set_name('RawLineEdit - Changelog')
156 | view.settings().set('gutter', False)
157 | view.settings().set('word_wrap', False)
158 | if has_phantom_support:
159 | mdpopups.add_phantom(
160 | view,
161 | 'changelog',
162 | sublime.Region(0),
163 | text,
164 | sublime.LAYOUT_INLINE,
165 | wrapper_class="raw-line-edit",
166 | css=CSS,
167 | on_navigate=self.on_navigate
168 | )
169 | else:
170 | view.run_command('insert', {"characters": text})
171 | view.set_read_only(True)
172 | view.set_scratch(True)
173 |
174 | def on_navigate(self, href):
175 | """Open links."""
176 | webbrowser.open_new_tab(href)
177 |
--------------------------------------------------------------------------------
/tests/validate_json_format.py:
--------------------------------------------------------------------------------
1 | """
2 | Validate JSON format.
3 |
4 | Licensed under MIT
5 | Copyright (c) 2012-2015 Isaac Muse
6 | """
7 | import re
8 | import codecs
9 | import json
10 |
11 | RE_LINE_PRESERVE = re.compile(r"\r?\n", re.MULTILINE)
12 | RE_COMMENT = re.compile(
13 | r'''(?x)
14 | (?P
15 | /\*[^*]*\*+(?:[^/*][^*]*\*+)*/ # multi-line comments
16 | | [ \t]*//(?:[^\r\n])* # single line comments
17 | )
18 | | (?P
19 | "(?:\\.|[^"\\])*" # double quotes
20 | | .[^/"']* # everything else
21 | )
22 | ''',
23 | re.DOTALL
24 | )
25 | RE_TRAILING_COMMA = re.compile(
26 | r'''(?x)
27 | (
28 | (?P
29 | , # trailing comma
30 | (?P[\s\r\n]*) # white space
31 | (?P\]) # bracket
32 | )
33 | | (?P
34 | , # trailing comma
35 | (?P[\s\r\n]*) # white space
36 | (?P\}) # bracket
37 | )
38 | )
39 | | (?P
40 | "(?:\\.|[^"\\])*" # double quoted string
41 | | .[^,"']* # everything else
42 | )
43 | ''',
44 | re.DOTALL
45 | )
46 | RE_LINE_INDENT_TAB = re.compile(r'^(?:(\t+)?(?:(/\*)|[^ \t\r\n])[^\r\n]*)?\r?\n$')
47 | RE_LINE_INDENT_SPACE = re.compile(r'^(?:((?: {4})+)?(?:(/\*)|[^ \t\r\n])[^\r\n]*)?\r?\n$')
48 | RE_TRAILING_SPACES = re.compile(r'^.*?[ \t]+\r?\n?$')
49 | RE_COMMENT_END = re.compile(r'\*/')
50 | PATTERN_COMMENT_INDENT_SPACE = r'^(%s *?[^\t\r\n][^\r\n]*)?\r?\n$'
51 | PATTERN_COMMENT_INDENT_TAB = r'^(%s[ \t]*[^ \t\r\n][^\r\n]*)?\r?\n$'
52 |
53 |
54 | E_MALFORMED = "E0"
55 | E_COMMENTS = "E1"
56 | E_COMMA = "E2"
57 | W_NL_START = "W1"
58 | W_NL_END = "W2"
59 | W_INDENT = "W3"
60 | W_TRAILING_SPACE = "W4"
61 | W_COMMENT_INDENT = "W5"
62 |
63 |
64 | VIOLATION_MSG = {
65 | E_MALFORMED: 'JSON content is malformed.',
66 | E_COMMENTS: 'Comments are not part of the JSON spec.',
67 | E_COMMA: 'Dangling comma found.',
68 | W_NL_START: 'Unnecessary newlines at the start of file.',
69 | W_NL_END: 'Missing a new line at the end of the file.',
70 | W_INDENT: 'Indentation Error.',
71 | W_TRAILING_SPACE: 'Trailing whitespace.',
72 | W_COMMENT_INDENT: 'Comment Indentation Error.'
73 | }
74 |
75 |
76 | class CheckJsonFormat(object):
77 | """
78 | Test JSON for format irregularities.
79 |
80 | - Trailing spaces.
81 | - Inconsistent indentation.
82 | - New lines at end of file.
83 | - Unnecessary newlines at start of file.
84 | - Trailing commas.
85 | - Malformed JSON.
86 | """
87 |
88 | def __init__(self, use_tabs=False, allow_comments=False):
89 | """Setup the settings."""
90 |
91 | self.use_tabs = use_tabs
92 | self.allow_comments = allow_comments
93 | self.fail = False
94 |
95 | def index_lines(self, text):
96 | """Index the char range of each line."""
97 |
98 | self.line_range = []
99 | count = 1
100 | last = 0
101 | for m in re.finditer('\n', text):
102 | self.line_range.append((last, m.end(0) - 1, count))
103 | last = m.end(0)
104 | count += 1
105 |
106 | def get_line(self, pt):
107 | """Get the line from char index."""
108 |
109 | line = None
110 | for r in self.line_range:
111 | if pt >= r[0] and pt <= r[1]:
112 | line = r[2]
113 | break
114 | return line
115 |
116 | def check_comments(self, text):
117 | """
118 | Check for JavaScript comments.
119 |
120 | Log them and strip them out so we can continue.
121 | """
122 |
123 | def remove_comments(group):
124 | return ''.join([x[0] for x in RE_LINE_PRESERVE.findall(group)])
125 |
126 | def evaluate(m):
127 | text = ''
128 | g = m.groupdict()
129 | if g["code"] is None:
130 | if not self.allow_comments:
131 | self.log_failure(E_COMMENTS, self.get_line(m.start(0)))
132 | text = remove_comments(g["comments"])
133 | else:
134 | text = g["code"]
135 | return text
136 |
137 | content = ''.join(map(lambda m: evaluate(m), RE_COMMENT.finditer(text)))
138 | return content
139 |
140 | def check_dangling_commas(self, text):
141 | """
142 | Check for dangling commas.
143 |
144 | Log them and strip them out so we can continue.
145 | """
146 |
147 | def check_comma(g, m, line):
148 | # ,] -> ] or ,} -> }
149 | self.log_failure(E_COMMA, line)
150 | if g["square_comma"] is not None:
151 | return g["square_ws"] + g["square_bracket"]
152 | else:
153 | return g["curly_ws"] + g["curly_bracket"]
154 |
155 | def evaluate(m):
156 | g = m.groupdict()
157 | return check_comma(g, m, self.get_line(m.start(0))) if g["code"] is None else g["code"]
158 |
159 | return ''.join(map(lambda m: evaluate(m), RE_TRAILING_COMMA.finditer(text)))
160 |
161 | def log_failure(self, code, line=None):
162 | """
163 | Log failure.
164 |
165 | Log failure code, line number (if available) and message.
166 | """
167 |
168 | if line:
169 | print("%s: Line %d - %s" % (code, line, VIOLATION_MSG[code]))
170 | else:
171 | print("%s: %s" % (code, VIOLATION_MSG[code]))
172 | self.fail = True
173 |
174 | def check_format(self, file_name):
175 | """Initiate the check."""
176 |
177 | self.fail = False
178 | comment_align = None
179 | with codecs.open(file_name, encoding='utf-8') as f:
180 | count = 1
181 | for line in f:
182 | indent_match = (RE_LINE_INDENT_TAB if self.use_tabs else RE_LINE_INDENT_SPACE).match(line)
183 | end_comment = (
184 | (comment_align is not None or (indent_match and indent_match.group(2))) and
185 | RE_COMMENT_END.search(line)
186 | )
187 | # Don't allow empty lines at file start.
188 | if count == 1 and line.strip() == '':
189 | self.log_failure(W_NL_START, count)
190 | # Line must end in new line
191 | if not line.endswith('\n'):
192 | self.log_failure(W_NL_END, count)
193 | # Trailing spaces
194 | if RE_TRAILING_SPACES.match(line):
195 | self.log_failure(W_TRAILING_SPACE, count)
196 | # Handle block comment content indentation
197 | if comment_align is not None:
198 | if comment_align.match(line) is None:
199 | self.log_failure(W_COMMENT_INDENT, count)
200 | if end_comment:
201 | comment_align = None
202 | # Handle general indentation
203 | elif indent_match is None:
204 | self.log_failure(W_INDENT, count)
205 | # Enter into block comment
206 | elif comment_align is None and indent_match.group(2):
207 | alignment = indent_match.group(1) if indent_match.group(1) is not None else ""
208 | if not end_comment:
209 | comment_align = re.compile(
210 | (PATTERN_COMMENT_INDENT_TAB if self.use_tabs else PATTERN_COMMENT_INDENT_SPACE) % alignment
211 | )
212 | count += 1
213 | f.seek(0)
214 | text = f.read()
215 |
216 | self.index_lines(text)
217 | text = self.check_comments(text)
218 | self.index_lines(text)
219 | text = self.check_dangling_commas(text)
220 | try:
221 | json.loads(text)
222 | except Exception as e:
223 | self.log_failure(E_MALFORMED)
224 | print(e)
225 | return self.fail
226 |
227 |
228 | if __name__ == "__main__":
229 | import sys
230 | cjf = CheckJsonFormat(False, True)
231 | cjf.check_format(sys.argv[1])
232 |
--------------------------------------------------------------------------------
/raw_line_edit.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Raw Line Edit.
4 |
5 | Licensed under MIT
6 | Copyright (c) 2013 - 2016 Isaac Muse
7 | """
8 | from __future__ import unicode_literals
9 | import sublime
10 | import sublime_plugin
11 | import codecs
12 | import re
13 | from os.path import exists
14 | try:
15 | from SubNotify.sub_notify import SubNotifyIsReadyCommand as Notify
16 | except Exception:
17 |
18 | class Notify(object):
19 | """Fallback notify class."""
20 |
21 | @classmethod
22 | def is_ready(cls):
23 | """Disable SubNotify by returning False."""
24 |
25 | return False
26 |
27 | CSS = """
28 |
46 | """
47 |
48 | RE_NEW_LINE = re.compile(r'(?:\r\n|(?!\r\n)[\n\r])')
49 |
50 |
51 | def process_lines(text):
52 | """Count line ending types and return buffer with only new lines."""
53 |
54 | crlf = []
55 | lf = []
56 | cr = []
57 | line = {'value': -1}
58 |
59 | def repl(m):
60 | """Replace."""
61 |
62 | line['value'] += 1
63 | end = m.group(0)
64 | if end == '\r\n':
65 | crlf.append(line['value'])
66 | elif end == '\n':
67 | lf.append(line['value'])
68 | else:
69 | cr.append((line['value']))
70 | return '\n'
71 |
72 | text = RE_NEW_LINE.sub(repl, text)
73 | return text, lf, cr, crlf
74 |
75 |
76 | def strip_buffer_glyphs(view):
77 | """Strip all glyphs from buffer to load back into view."""
78 |
79 | line = -1
80 | more = True
81 | last_value = -1
82 | lines = []
83 | mappings = {'crlf': '\r\n', 'cr': '\r', 'lf': '\n'}
84 | while more:
85 | line += 1
86 | value = view.text_point(line, 0)
87 | region = None
88 | for line_type in ('crlf', 'cr', 'lf'):
89 | regions = view.get_regions('rle_line_%d_%s' % (line, line_type))
90 | if regions:
91 | view.erase_regions('rle_line_%d_%s' % (line, line_type))
92 | region = regions[0]
93 | break
94 | if region is not None:
95 | view.erase_phantoms('rle_line_%d' % line)
96 | lines.append(view.substr(view.line(region)) + mappings[line_type])
97 | if value == last_value:
98 | more = False
99 | last_value = value
100 | return ''.join(lines)
101 |
102 |
103 | def convert_buffers():
104 | """Operate on unsaved buffers."""
105 |
106 | return bool(sublime.load_settings("raw_line_edit.sublime-settings").get("operate_on_unsaved_buffers", False))
107 |
108 |
109 | def get_encoding(view):
110 | """Get the file encoding."""
111 |
112 | encoding = view.encoding()
113 | mapping = [
114 | ("with BOM", ""),
115 | ("Windows", "cp"),
116 | ("-", "_"),
117 | (" ", "")
118 | ]
119 | encoding = view.encoding()
120 | m = re.match(r'.+\((.*)\)', encoding)
121 | if m is not None:
122 | encoding = m.group(1)
123 |
124 | for item in mapping:
125 | encoding = encoding.replace(item[0], item[1])
126 |
127 | return "utf_8" if encoding in ["Undefined", "Hexidecimal"] else encoding
128 |
129 |
130 | def notify(msg):
131 | """Notify message."""
132 |
133 | settings = sublime.load_settings("raw_line_edit.sublime-settings")
134 | if settings.get("use_sub_notify", False) and Notify.is_ready():
135 | sublime.run_command("sub_notify", {"title": "RawLineEdit", "msg": msg})
136 | else:
137 | sublime.status_message(msg)
138 |
139 |
140 | def error(msg):
141 | """Error message."""
142 |
143 | settings = sublime.load_settings("raw_line_edit.sublime-settings")
144 | if settings.get("use_sub_notify", False) and Notify.is_ready():
145 | sublime.run_command("sub_notify", {"title": "RawLineEdit", "msg": msg, "level": "error"})
146 | else:
147 | sublime.error_message("RawLineEdit:\n%s" % msg)
148 |
149 |
150 | class RawLineTextBuffer(object):
151 | """Text buffer."""
152 |
153 | bfr = None
154 | syntax = None
155 | endings = None
156 | view = None
157 |
158 | @classmethod
159 | def set_buffer(cls, view):
160 | """Read buffer from view and strip new line glyphs."""
161 |
162 | cls.bfr = strip_buffer_glyphs(view)
163 |
164 | @classmethod
165 | def clear_buffer(cls):
166 | """Clear the buffer object."""
167 |
168 | cls.bfr = None
169 | cls.view = None
170 |
171 | @classmethod
172 | def check_loading(cls, view):
173 | """Check if file is done loading yet before applying buffer."""
174 |
175 | cls.view = view
176 | sublime.set_timeout(cls.poll_loading, 300)
177 |
178 | @classmethod
179 | def poll_loading(cls):
180 | """Check if file is done loading, and if so, update view with buffer."""
181 |
182 | if cls.view.is_loading():
183 | sublime.set_timeout(cls.poll_loading, 300)
184 | else:
185 | cls.view.run_command("write_raw_line_text")
186 |
187 |
188 | class WriteRawLineTextCommand(sublime_plugin.TextCommand):
189 | """Write buffer to view."""
190 |
191 | def run(self, edit):
192 | """Write the unsaved buffer to the view."""
193 |
194 | if RawLineTextBuffer.bfr is None:
195 | return
196 | self.view.replace(edit, sublime.Region(0, self.view.size()), RawLineTextBuffer.bfr)
197 | RawLineTextBuffer.clear_buffer()
198 |
199 |
200 | class ToggleRawLineEditCommand(sublime_plugin.TextCommand):
201 | """Toggle raw line edit mode."""
202 |
203 | def disable_rle(self, edit):
204 | """Disable raw line ending mode."""
205 |
206 | # Save raw line ending changes
207 | if self.view.is_dirty():
208 | if sublime.ok_cancel_dialog("Raw Line Edit:\nFile has unsaved changes. Save?", "Save"):
209 | self.view.run_command("save")
210 |
211 | # Get the settings
212 | settings = self.view.settings()
213 | file_name = settings.get("RawLineEditFilename")
214 | syntax = settings.get("RawLineEditSyntax")
215 | buffer_endings = settings.get("RawLineBuffer", None)
216 |
217 | # Strip the buffer of glyphs and prepare to write
218 | # the stripped buffer back to the view
219 | if buffer_endings is not None:
220 | RawLineTextBuffer.set_buffer(self.view)
221 |
222 | # Open temp view if only one view is open,
223 | # so not to close the window when we remove the view.
224 | window = self.view.window()
225 | temp = None
226 | if len(window.views()) <= 1:
227 | temp = window.new_file()
228 |
229 | # Close raw line view
230 | window.focus_view(self.view)
231 | window.run_command("close_file")
232 |
233 | # Open the file on disk
234 | new_view = window.open_file(file_name)
235 |
236 | # Close temp view if needed
237 | if temp is not None:
238 | window.focus_view(temp)
239 | window.run_command("close_file")
240 |
241 | # Set view settings
242 | window.focus_view(new_view)
243 | new_view.set_syntax_file(syntax)
244 |
245 | # Reapply unsaved buffer if needed
246 | if buffer_endings is not None:
247 | new_view.set_line_endings(buffer_endings)
248 | RawLineTextBuffer.check_loading(new_view)
249 |
250 | def enable_rle(self, edit, file_name):
251 | """Enable raw line ending mode."""
252 |
253 | if self.view.is_dirty():
254 | if convert_buffers():
255 | msg = (
256 | "File has unsaved changes. If you choose to 'continue' without a 'save', "
257 | "the view buffer will be parsed as the source.\n\nSave?"
258 | )
259 | else:
260 | msg = (
261 | "File has unsaved changes. If you choose to 'continue' without a 'save', "
262 | "changes will be discarded and the file will be parsed from disk.\n\nSave?"
263 | )
264 | value = sublime.yes_no_cancel_dialog(msg, "Save", "Continue")
265 | if value == sublime.DIALOG_YES:
266 | # Save the file
267 | self.view.run_command("save")
268 | elif value == sublime.DIALOG_NO:
269 | # Convert the unsaved buffer
270 | if convert_buffers():
271 | self.enable_buffer_rle(edit, file_name)
272 | return
273 | else:
274 | if file_name is None:
275 | error("File must exist on disk!")
276 | return
277 | else:
278 | notify("Changes discarded.")
279 | else:
280 | return
281 |
282 | if file_name is None or not exists(file_name):
283 | if convert_buffers():
284 | self.enable_buffer_rle(edit)
285 | else:
286 | error("File must exist on disk!")
287 | return
288 |
289 | # Convert the file on disk to a raw line view
290 | encoding = get_encoding(self.view)
291 | try:
292 | self.show_rle(edit, file_name, encoding)
293 | except Exception:
294 | self.show_rle(edit, file_name, "utf-8")
295 |
296 | def show_rle(self, edit, file_name, encoding):
297 | """
298 | Read the file from disk converting actual lines to glyphs.
299 |
300 | Present the info in raw line view.
301 | """
302 | with codecs.open(file_name, "r", encoding) as f:
303 | text, lf, cr, crlf = process_lines(f.read())
304 | self.view.replace(edit, sublime.Region(0, self.view.size()), text)
305 | self.view.set_line_endings("Unix")
306 | settings = self.view.settings()
307 | settings.set("RawLineEdit", True)
308 | settings.set("RawLineEditSyntax", settings.get('syntax'))
309 | settings.set("RawLineEditFilename", file_name)
310 | self.view.assign_syntax(settings.get('syntax'))
311 | self.view.set_scratch(True)
312 | self.view.set_read_only(True)
313 |
314 | self.update_phantoms(crlf, cr, lf)
315 |
316 | def read_buffer(self):
317 | """Read the unsaved buffer and replace with new line glyphs."""
318 |
319 | endings = {
320 | "Windows": "\r\n",
321 | "Unix": "\n",
322 | "CR": "\r"
323 | }
324 | line_ending = endings[self.view.line_endings()]
325 | bfr = []
326 | for line in self.view.split_by_newlines(sublime.Region(0, self.view.size())):
327 | bfr.append(self.view.substr(line) + line_ending)
328 | return "".join(bfr)
329 |
330 | def enable_buffer_rle(self, edit, file_name=None):
331 | """Enable the raw line mode on an unsaved buffer."""
332 |
333 | if self.view.is_read_only():
334 | self.view.set_read_only(False)
335 | settings = self.view.settings()
336 | self.view.settings().set("RawLineBuffer", self.view.line_endings())
337 | text, lf, cr, crlf = process_lines(self.read_buffer())
338 | self.view.replace(edit, sublime.Region(0, self.view.size()), text)
339 | self.view.set_line_endings("Unix")
340 | settings.set("RawLineEdit", True)
341 | settings.set("RawLineEditSyntax", self.view.settings().get('syntax'))
342 | if file_name is not None:
343 | settings.set("RawLineEditFilename", file_name)
344 | self.view.set_scratch(True)
345 | self.view.set_read_only(True)
346 | self.update_phantoms(crlf, cr, lf)
347 |
348 | def disable_buffer_rle(self, edit):
349 | """Disable the raw line mode on an unsaved buffer."""
350 |
351 | if self.view.is_dirty():
352 | if sublime.ok_cancel_dialog("Raw Line Edit:\nFile has unsaved changes. Save?", "Save"):
353 | self.view.run_command("save")
354 | self.disable_rle(edit)
355 | return
356 | win = self.view.window()
357 | new_view = win.new_file()
358 | settings = self.view.settings()
359 | syntax = settings.get("RawLineEditSyntax")
360 | line_endings = settings.get("RawLineBuffer")
361 | bfr = strip_buffer_glyphs(self.view)
362 | new_view.replace(edit, sublime.Region(0, self.view.size()), bfr)
363 | new_view.set_line_endings(line_endings)
364 | new_view.set_syntax_file(syntax)
365 | win.focus_view(self.view)
366 | win.run_command("close_file")
367 | win.focus_view(new_view)
368 |
369 | def update_phantoms(self, crlf, cr, lf):
370 | """Update phantoms."""
371 |
372 | for line in crlf:
373 | pt = self.view.text_point(line + 1, 0) - 1
374 | region = sublime.Region(pt)
375 | self.view.add_phantom(
376 | 'rle_line_%d' % line,
377 | region,
378 | '%s¤¬' % CSS,
379 | sublime.LAYOUT_INLINE
380 | )
381 | self.view.add_regions('rle_line_%d_crlf' % line, [region], '', '', sublime.HIDDEN)
382 | for line in cr:
383 | pt = self.view.text_point(line + 1, 0) - 1
384 | region = sublime.Region(pt)
385 | self.view.add_phantom(
386 | 'rle_line_%d' % line,
387 | region,
388 | '%s¤' % CSS,
389 | sublime.LAYOUT_INLINE
390 | )
391 | self.view.add_regions('rle_line_%d_cr' % line, [region], '', '', sublime.HIDDEN)
392 | for line in lf:
393 | pt = self.view.text_point(line + 1, 0) - 1
394 | region = sublime.Region(pt)
395 | self.view.add_phantom(
396 | 'rle_line_%d' % line,
397 | region,
398 | '%s¬' % CSS,
399 | sublime.LAYOUT_INLINE
400 | )
401 | self.view.add_regions('rle_line_%d_lf' % line, [region], '', '', sublime.HIDDEN)
402 |
403 | def run(self, edit):
404 | """Toggle the raw line mode."""
405 |
406 | file_name = self.view.file_name()
407 | settings = self.view.settings()
408 |
409 | if (file_name is None or not exists(file_name)) and settings.get("RawLineEdit", False):
410 | self.disable_buffer_rle(edit)
411 | elif settings.get("RawLineEdit", False):
412 | self.disable_rle(edit)
413 | elif not settings.get("RawLineEdit", False):
414 | self.enable_rle(edit, file_name)
415 |
416 |
417 | class PopupRawLineEditCommand(sublime_plugin.TextCommand):
418 | """Popup command."""
419 |
420 | def popup_rle(self, file_name):
421 | """Popup raw line edit view."""
422 |
423 | if self.view.is_dirty():
424 | if convert_buffers():
425 | msg = (
426 | "File has unsaved changes. If you choose to 'continue' without a 'save', "
427 | "the view buffer will be parsed as the source.\n\nSave?"
428 | )
429 | else:
430 | msg = (
431 | "File has unsaved changes. If you choose to 'continue' without a 'save', "
432 | "changes will be discarded and the file will be parsed from disk.\n\nSave?"
433 | )
434 | value = sublime.yes_no_cancel_dialog(msg, "Save", "Discard Changes", "Cancel")
435 | if value == sublime.DIALOG_YES:
436 | self.view.run_command("save")
437 | elif value == sublime.DIALOG_NO:
438 | # Convert the unsaved buffer
439 | if convert_buffers():
440 | self.enable_buffer_rle(file_name)
441 | return
442 | else:
443 | if file_name is None:
444 | error("File must exist on disk!")
445 | return
446 | else:
447 | notify("Changes discarded.")
448 | else:
449 | return
450 |
451 | if file_name is None or not exists(file_name):
452 | if convert_buffers():
453 | self.enable_buffer_rle()
454 | else:
455 | error("File must exist on disk!")
456 | return
457 |
458 | encoding = get_encoding(self.view)
459 | try:
460 | self.show_rle(file_name, encoding)
461 | except Exception:
462 | self.show_rle(file_name, "utf-8")
463 |
464 | def read_buffer(self):
465 | """Read the unsaved buffer and replace with new line glyphs."""
466 |
467 | endings = {
468 | "Windows": "\r\n",
469 | "Unix": "\n",
470 | "CR": "\r"
471 | }
472 | line_ending = endings[self.view.line_endings()]
473 | bfr = []
474 | for line in self.view.split_by_newlines(sublime.Region(0, self.view.size())):
475 | bfr.append(self.view.substr(line) + line_ending)
476 | return "".join(bfr)
477 |
478 | def get_output_panel(self):
479 | """Get output panel."""
480 |
481 | win = self.view.window()
482 | view = win.find_output_panel('raw_line_edit_view')
483 | if view is not None:
484 | win.destroy_output_panel('raw_line_edit_view')
485 | return win.get_output_panel('raw_line_edit_view')
486 |
487 | def enable_buffer_rle(self, file_name=None):
488 | """Enable the raw line mode on an unsaved buffer."""
489 |
490 | view = self.get_output_panel()
491 | view.set_line_endings("Unix")
492 | view.set_read_only(False)
493 |
494 | RawLinesEditReplaceCommand.region = sublime.Region(0, view.size())
495 | RawLinesEditReplaceCommand.text, lf, cr, crlf = process_lines(self.read_buffer())
496 | view.run_command("raw_lines_edit_replace")
497 | view.sel().clear()
498 | settings = view.settings()
499 | view.assign_syntax(self.view.settings().get('syntax'))
500 | settings.set("RawLineEdit", True)
501 | settings.set("RawLineEditSyntax", self.view.settings().get('syntax'))
502 | settings.set("RawLineEditPopup", True)
503 | settings.set("RawLineBuffer", self.view.line_endings())
504 | if file_name is not None:
505 | settings.set("RawLineEditFilename", file_name)
506 | view.set_scratch(True)
507 | view.set_read_only(True)
508 |
509 | self.update_phantoms(view, crlf, cr, lf)
510 | self.view.window().run_command("show_panel", {"panel": "output.raw_line_edit_view"})
511 |
512 | def show_rle(self, file_name, encoding):
513 | """Show the raw line view popup."""
514 |
515 | try:
516 | view = self.get_output_panel()
517 | view.set_line_endings("Unix")
518 | with codecs.open(file_name, "r", encoding) as f:
519 | view.set_read_only(False)
520 | RawLinesEditReplaceCommand.region = sublime.Region(0, view.size())
521 | RawLinesEditReplaceCommand.text, lf, cr, crlf = process_lines(f.read())
522 | view.run_command("raw_lines_edit_replace")
523 | view.sel().clear()
524 | view.assign_syntax(self.view.settings().get('syntax'))
525 | view.settings().set("RawLineEditSyntax", self.view.settings().get('syntax'))
526 | view.settings().set("RawLineEdit", True)
527 | view.settings().set("RawLineEditFilename", file_name)
528 | view.settings().set("RawLineEditPopup", True)
529 | view.set_scratch(True)
530 | view.set_read_only(True)
531 |
532 | self.update_phantoms(view, crlf, cr, lf)
533 | self.view.window().run_command("show_panel", {"panel": "output.raw_line_edit_view"})
534 | except Exception:
535 | self.view.window().run_command("hide_panel", {"panel": "output.raw_line_edit_view"})
536 | raise
537 |
538 | def update_phantoms(self, view, crlf, cr, lf):
539 | """Update phantoms."""
540 |
541 | for line in crlf:
542 | pt = view.text_point(line + 1, 0) - 1
543 | region = sublime.Region(pt)
544 | view.add_phantom(
545 | 'rle_line_%d' % line,
546 | region,
547 | '%s¤¬' % CSS,
548 | sublime.LAYOUT_INLINE
549 | )
550 | view.add_regions('rle_line_%d_crlf' % line, [region], '', '', sublime.HIDDEN)
551 | for line in cr:
552 | pt = view.text_point(line + 1, 0) - 1
553 | region = sublime.Region(pt)
554 | view.add_phantom(
555 | 'rle_line_%d' % line,
556 | region,
557 | '%s¤' % CSS,
558 | sublime.LAYOUT_INLINE
559 | )
560 | view.add_regions('rle_line_%d_cr' % line, [region], '', '', sublime.HIDDEN)
561 | for line in lf:
562 | pt = view.text_point(line + 1, 0) - 1
563 | region = sublime.Region(pt)
564 | view.add_phantom(
565 | 'rle_line_%d' % line,
566 | region,
567 | '%s¬' % CSS,
568 | sublime.LAYOUT_INLINE
569 | )
570 | view.add_regions('rle_line_%d_lf' % line, [region], '', '', sublime.HIDDEN)
571 |
572 | def run(self, edit):
573 | """Popup panel with raw line view."""
574 |
575 | file_name = self.view.file_name()
576 | settings = self.view.settings()
577 | if (not settings.get("RawLineEdit", False)) and not settings.get('RawLineEditPopup', False):
578 | self.popup_rle(file_name)
579 |
580 |
581 | class RawLineInsertCommand(sublime_plugin.TextCommand):
582 | """Insert text in view."""
583 |
584 | def run(self, edit, style="Unix"):
585 | """Insert text."""
586 |
587 | for s in reversed(self.view.sel()):
588 | line_regions = self.view.lines(s)
589 | for region in line_regions:
590 | row = self.view.rowcol(region.begin())[0]
591 | if row >= 0:
592 | r = None
593 | for line_type in ('crlf', 'cr', 'lf'):
594 | temp = self.view.get_regions('rle_line_%d_%s' % (row, line_type))
595 | if temp:
596 | r = temp[0]
597 | break
598 | if r is not None:
599 | self.view.erase_regions('rle_line_%d_%s' % (row, line_type))
600 | self.view.erase_phantoms('rle_line_%d' % row)
601 |
602 | pt = self.view.text_point(row + 1, 0) - 1
603 | r = sublime.Region(pt)
604 | if style == "Unix":
605 | temp = '%s¬'
606 | line_type = 'lf'
607 | elif style == "Windows":
608 | temp = '%s¤¬'
609 | line_type = 'crlf'
610 | else:
611 | temp = '%s¤'
612 | line_type = 'cr'
613 | self.view.add_phantom(
614 | 'rle_line_%d' % row,
615 | r,
616 | temp % CSS,
617 | sublime.LAYOUT_INLINE
618 | )
619 | self.view.add_regions('rle_line_%d_%s' % (row, line_type), [r], '', '', sublime.HIDDEN)
620 |
621 |
622 | class RawLinesEditReplaceCommand(sublime_plugin.TextCommand):
623 | """Replace text in view."""
624 |
625 | text = None
626 | region = None
627 |
628 | def run(self, edit):
629 | """Replace text."""
630 |
631 | cls = RawLinesEditReplaceCommand
632 | if cls.text is not None and cls.region is not None:
633 | self.view.replace(edit, cls.region, cls.text)
634 | cls.text = None
635 | cls.region = None
636 |
637 |
638 | class RawLineEditListener(sublime_plugin.EventListener):
639 | """RawLineEdit Listener."""
640 |
641 | def on_pre_save(self, view):
642 | """Convert raw line mode back to normal mode before save."""
643 |
644 | if view.settings().get("RawLineEdit", False) and not view.settings().get('RawLineEditPopup', False):
645 | RawLinesEditReplaceCommand.region = sublime.Region(0, view.size())
646 | RawLinesEditReplaceCommand.text = strip_buffer_glyphs(view)
647 | view.set_read_only(False)
648 | view.run_command("raw_lines_edit_replace")
649 | view.set_read_only(True)
650 |
651 | def on_post_save(self, view):
652 | """Convert view back to raw line mode after save."""
653 |
654 | if view.settings().get("RawLineEdit", False) and not view.settings().get('RawLineEditPopup', False):
655 | file_name = view.file_name()
656 | if file_name is not None:
657 | view.settings().set("RawLineEditFilename", file_name)
658 | if view.settings().set("RawLineBuffer", None) is not None:
659 | view.settings().erase("RawLineBuffer")
660 |
661 | view.set_read_only(False)
662 | RawLinesEditReplaceCommand.region = sublime.Region(0, view.size())
663 | RawLinesEditReplaceCommand.text, lf, cr, crlf = process_lines(
664 | view.substr(RawLinesEditReplaceCommand.region)
665 | )
666 | view.run_command("raw_lines_edit_replace")
667 |
668 | for line in crlf:
669 | pt = view.text_point(line + 1, 0) - 1
670 | region = sublime.Region(pt)
671 | view.add_phantom(
672 | 'rle_line_%d' % line,
673 | region,
674 | '%s¤¬' % CSS,
675 | sublime.LAYOUT_INLINE
676 | )
677 | view.add_regions('rle_line_%d_crlf' % line, [region], '', '', sublime.HIDDEN)
678 | for line in cr:
679 | pt = view.text_point(line + 1, 0) - 1
680 | region = sublime.Region(pt)
681 | view.add_phantom(
682 | 'rle_line_%d' % line,
683 | region,
684 | '%s¤' % CSS,
685 | sublime.LAYOUT_INLINE
686 | )
687 | view.add_regions('rle_line_%d_cr' % line, [region], '', '', sublime.HIDDEN)
688 | for line in lf:
689 | pt = view.text_point(line + 1, 0) - 1
690 | region = sublime.Region(pt)
691 | view.add_phantom(
692 | 'rle_line_%d' % line,
693 | region,
694 | '%s¬' % CSS,
695 | sublime.LAYOUT_INLINE
696 | )
697 | view.add_regions('rle_line_%d_lf' % line, [region], '', '', sublime.HIDDEN)
698 |
699 | view.set_scratch(True)
700 | view.set_read_only(True)
701 |
702 | def on_query_context(self, view, key, operator, operand, match_all):
703 | """Handle raw line mode shortcuts."""
704 |
705 | settings = view.settings()
706 | return (
707 | settings.get("RawLineEdit", False) and key.startswith("raw_line_edit") and
708 | not settings.get('RawLineEditPopup', False)
709 | )
710 |
--------------------------------------------------------------------------------