I am working with a fixed-width file where all lines start with certain strings to denote what they contain.
TXX 12345 1111
TXY 123 1 2222
TXZ 1 2 3 4 5
What I want to happen is that I want to be able to add rulers or any form of formatting to rows that start with the specified text. (For example, I want to be able to set the line to red if the line starts with TXX, but blue if the row starts wtih TXY and so on)
What is the first step towards being able to do this?
Generally speaking, most roads here lead to a plugin of some sort that's doing work for you, though conceivably you could also get some coloring going using a custom syntax definition and alterations to your color scheme.
Which one is the correct one depends on circumstance and what works best for you. The following are some samples, which will work with the output you provided above but which could probably be made more robust (again depending on your use case); think proof of concept stuff.
Rulers can only be applied to the file as a whole, not to specific lines. So for something like that you're looking at a plugin which, every time the cursor moves, tries to look at the current line to see what it is and then sets up rulers based on knowing what the line looks like.
A quick example of that is the following; the event listener will only apply to files that have the _fixed_rulers
setting applied; simplistically, while you have your file open you can enter view.settings().set("_fixed_rulers", True)
in the Sublime console, or if you have a syntax you could put the setting into syntax specific settings, etc.
import sublime
import sublime_plugin
def _get_rulers(line):
if line.startswith('TXX'):
return [4, 10]
if line.startswith('TXY'):
return [4, 8, 10]
if line.startswith('TXZ'):
return [4, 6, 8, 10, 12]
return []
class RulerListener(sublime_plugin.ViewEventListener):
@classmethod
def is_applicable(cls, settings):
return settings.get("_fixed_rulers", False)
def on_selection_modified_async(self):
# Cursor position of the first selection; get the full text of the
# line its on
pt = self.view.sel()[0].b
line = self.view.substr(self.view.line(pt))
self.view.settings().set("rulers", _get_rulers(line))
Since there can be multiple selections but rulers are not line specific, this uses the line the first cursor (based on position, not selection order) and applies rulers to the file based on that.
Colors can be applied to regions of content via a plugin, in a variety of styles (outlined only, underlined, filled, etc), and the API also allows you to find text regions via regex.
So it's also possible to have regions assigned that give things the color you want. A simple example of that would be this command, which will add/update the regions in the file that's active when you execute the color_line_regions
command.
import sublime
import sublime_plugin
class ColorLineRegionsCommand(sublime_plugin.TextCommand):
def run(self, edit):
v = self.view
v.add_regions('_txx', v.find_all('^TXX.*$'), 'region.redish')
v.add_regions('_txy', v.find_all('^TXY.*$'), 'region.bluish')
v.add_regions('_txz', v.find_all('^TXZ.*$'), 'region.purplish')
This example is hard coded and requires you to manually invoke the command; you could also have this trigger in response to a file with a specific name opening, and so on.
As defined here this is a one time thing; if you are actively modifying the content of files, adding or changing lines will not adjust regions unless you run the command again (or, have an event listener listen for on_modified_async
and trigger this after a delay, etc).
Another potential option is creating a custom syntax definition that recognizes the content of the file and applies the appropriate scopes to color things.
This is a much more complex option (the example below is very bare bones and not nearly production ready, but is a good simple test) in that it requires you to construct the syntax definition, but can yield good results if you put in the work.
What you would actually want to do is create your own custom scopes in your syntax, probably with much more robust rules, and then augment your color scheme to match those. Here we're just hackily using scopes that equate to the proper colors if you happen to be using Mariana as your color scheme.
%YAML 1.2
---
# See http://www.sublimetext.com/docs/syntax.html
file_extensions:
- fixed
scope: text.plain.fixed
name: Fixed Field Data
contexts:
main:
- match: '^TXX.*'
scope: variable.language.python
- match: '^TXY.*'
scope: variable.function.python
- match: '^TXZ.*'
scope: keyword.declaration.class.python
The ultimate solution may be a mixture of these; perhaps you want the syntax to provide colors and the rulers plugin to make things easier to view as well (as a bonus, with a custom syntax you can have syntax specific settings, which makes the first plugin easy to deploy when files open).
The above examples just scratch the surface; be sure to check out the API Reference for information on how the plugins are working and for more details. There are also a variety of videos that teach how to create and use plugins on my YouTube channel.