Add formatting to certain lines that begin with specific strings in Sublime Text 3? - sublimetext3

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
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.
Regions
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).
Syntax Definition
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
A Mix
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.

Related

Python Inquirer Module: Remove Choices When Done (Using Curses)

NOTE: Although I give a lot of info on Inquirer, I'm pretty sure that most of it won't apply (just being safe). For my actual question about curses, its at the bottom.
I'm using the Inquirer module in Python 3 to allow the user to select a value from a list. I run this:
import inquirer
choice = inquirer.prompt([inquirer.List("size",message="Which size do you need?",choices=["Large", "Medium", "Small"])
And I'm given this:
[?] What size do you need?: Medium
Large
> Medium
Small
And using the up and down keys, I can change my selection, and hit enter to choose, after which the "choice" variable contains the value I selected. The issue is: Once the selection is done, the choices still show. I want to delete them when done. I'm currently using ANSI Escape Codes to delete the choices from onscreen when done, where x is the number of choices:
import sys
for i in range (x+1):
sys.stdout.write('\x1b[1A')
sys.stdout.write('\x1b[2K')
Which leaves the printed text as:
[?] What size do you need?: Medium
The issue is, ANSI escape codes aren't universal. I want to use a solution that works on all terminals, preferably curses, but curses isn't very friendly to new users, so I was wondering if anyone knew how to use curses to "delete x lines above current position". Thanks!
curses, as such, would erase the whole display (which is probably not what you want). A low-level terminfo/termcap approach might seem promising, but while ECMA-48 does define a sequence (ED, with parameter 1) which erases above the current position, there is no predefined terminfo/termcap capability which corresponds to this. All that you will find there is the capability for erasing to the end of the screen, or erasing the whole screen.
"ANSI sequences" is an obsolete term. Referring to ECMA-48, you could do
sys.stdout.write('\x1b[1J')
after moving the cursor to the last location you would like to erase.

Custom syntax in Sublime Text 3

I'm struggling to find out how to create a new syntax highlighting in Sublime Text 3 using the new .sublime-syntax style definition (most previous answers relate to old ways of doing it).
As of Sublime Text Build 3084, a new syntax definition format has been added, with the .sublime-syntax extension.
I can find the:
syntax rules
scope naming rules
colour scheme rules
But I can't find the most basic piece of information detailing how these tie together!
I'm not trying to create a theme, or tweaking an existing syntax definition. I just want to create syntax highlighting to files with an extension I plan on using for my own purposes.
In the syntax definition I have to specify a scope (e.g. scope: source.c) but where does that scope file live? Or rather, where do I create my scope file, and how do I name it, so that it loads?
How do I know that my syntax file, and the scope file it uses, are loaded and applied successfully?
Are there any compile or refresh steps, or does everything automatically reload?
Thanks.
A full discussion of how to create a custom syntax is well outside the bounds of something as simple as a Stack Overflow answer. Also I think you're making your problem more complicated than it actually is (although creating a syntax is pretty complicated in general).
In order to walk you through the steps that you would take to create a custom syntax, here's an example.
To start with, create a file with the following contents and save it somewhere as sample.ec, and leave the file open:
// This is a line comment
if (x == 2)
y = 1
else
z = 1
You'll notice that the syntax for this file is set to Plain Text (see the status line in the lower right), which is the default syntax for files that are unknown to Sublime.
Now, select Tools > Developer > New Syntax... from the menu. A buffer with the following will appear. Use File > Save to save the file; the location will default to your User package. The name you give it is not important, but make sure that the extension is sublime-syntax. In my example I'm calling my file Sample.sublime-syntax.
%YAML 1.2
---
# See http://www.sublimetext.com/docs/3/syntax.html
file_extensions:
- ec
scope: source.example-c
contexts:
main:
# Strings begin and end with quotes, and use backslashes as an escape
# character
- match: '"'
scope: punctuation.definition.string.begin.example-c
push: double_quoted_string
# Comments begin with a '//' and finish at the end of the line
- match: '//'
scope: punctuation.definition.comment.example-c
push: line_comment
# Keywords are if, else for and while.
# Note that blackslashes don't need to be escaped within single quoted
# strings in YAML. When using single quoted strings, only single quotes
# need to be escaped: this is done by using two single quotes next to each
# other.
- match: '\b(if|else|for|while)\b'
scope: keyword.control.example-c
# Numbers
- match: '\b(-)?[0-9.]+\b'
scope: constant.numeric.example-c
double_quoted_string:
- meta_scope: string.quoted.double.example-c
- match: '\\.'
scope: constant.character.escape.example-c
- match: '"'
scope: punctuation.definition.string.end.example-c
pop: true
line_comment:
- meta_scope: comment.line.example-c
- match: $
pop: true
Now open the Sublime Console with View > Show Console or press the associated key binding. You'll see that the last line in the console is this:
generating syntax summary
Leaving the console open, click in the syntax file and perform another save operation again without changing anything. The same line appears in the console again.
Are there any compile or refresh steps, or does everything automatically reload?
As seen here, every time you modify the syntax definition, the file is recompiled and the results are cached. So there are no compile steps (other than saving) and nothing you need to do in order to refresh anything.
Now lets turn our attention back to the sample file. It's still open, and the syntax still says that it's Plain Text.
Now close the file and re-open it again; a shortcut for this is to use File > Open Recent > Reopen Closed File or it's associated key binding.
Notice that now that the file is re-opened, there are several changes. Firstly, the syntax name in the bottom right side of the window says Sample (or whatever you named your sublime-syntax file above). For another, the contents of the file are now syntax highlighted.
The colors you see are dependent on the color scheme you use, but an example might look like this:
// This is a line comment
if (x == 2)
y = 1
else
z = 1
How do I know that my syntax file, and the scope file it uses, are loaded and applied successfully?
You can see that the syntax file was compiled by the lack of an error message when you save your changes, and you can tell that it's applied by trying to use the syntax.
Here the syntax is being used automatically, but you'll find that if you check View > Syntax in the menu or click the current syntax name in the bottom right of the window, your syntax will appear there. Similarly there is now an entry in the command palette named Set Syntax: Sample (or whatever).
That leads us into your last question. If you go back to your sublime-syntax file, you'll see this at the top:
# See http://www.sublimetext.com/docs/3/syntax.html
file_extensions:
- ec
scope: source.example-c
The first thing to note is that file_extensions includes ec, and our sample file is called sample.ec; thus this syntax applies to it automatically due to it's name.
Now switch into the sample.ec file, place the cursor somewhere in the buffer and use Tools > Developer > Show Scope Name or press the associated key.
The content of the popup that appears will vary depending on where in the file the cursor is located, but the common point is that the scope that appears always starts with source.example-c.
In the syntax definition I have to specify a scope (e.g. scope: source.c) but where does that scope file live? Or rather, where do I create my scope file, and how do I name it, so that it loads?
As seen here, there is no such thing as a "scope file"; the sublime-syntax file directly specifies the scope as part of the syntax rules, so it's the only file that you need to create in order to create a syntax. It may look like a filename, but it is not one.
The scopes that are applied in the syntax matching rules in the syntax need to coincide with the scopes in your color scheme in order to be syntax highlighted; that's why you should use the scope naming rules to use the common set of scopes that all syntaxes share unless you're also planning to make a color scheme to go along with your syntax, but unless you use the recommended scopes, your syntax won't work well with other color schemes and your color scheme won't work well for other syntaxes.
From this starting point you can modify the sublime-syntax file here in order to make it highlight files the way you want. That would include changing the base scope at the top, applying an appropriate extension, and then including all of the rules that match your language.
As mentioned above, creating the actual rules to match your file is the most complicated part of creating a syntax unless your file format is very simplistic. It's outside the scope of something that could be conveyed in a Stack Overflow answer, but the official documentation linked above gives you some information on it.
Apart from looking at existing syntax files to see how they're doing what they do, you can also ask more directed questions on the Sublime forum.
I will shortly answer your questions, someone else can feel free to write a longer guide:
You put your syntax definitions inside a package: Select Preferences > Browse Packages... this should open your file explorer. There you can either create a new folder for a new package or use the User folder, which is the default user package. Inside that create a file YourSyntax.sublime-syntax.
You can open the ST console ctrl+` and it will output that the syntax is loaded and potential errors. You can also press ctrl+shift+p and write Set Syntax: YourSyntax in a buffer to directly see it.
You just need to save the file and it will reload the syntax definition.

Writing an autocomplete plugin in Sublime Text

Within my company we have an XML-based notation. Among other features, it is possible to define references from one XML document into another. I would like to enable autocompletion in Sublime so that whenever I am adding a reference, the possible files (i.e. XML files within the same project) and link points (i.e. symbols within that file) get offered as recommendations.
So far, I have found a lot of plugins that enable autocomplete for, say, HTML, PHP or LaTeX. However, I have the feeling the code base is too complex for a somewhat simple task. Is there, for instance, some vanilla function that generates completions based on an arbitrary array received as parameter? I would create the logic to determine what is a symbol and derive said array, but the whole process seems somewhat cumbersome to me.
(As a note: I can program in Python and have fiddled with other Sublime features, such as snippets, but these packages seem to be much more complex than it feels necessary.)
The base to create the completions entry is not to complicated. You now need to fill the array with the correct values (this could be done via a project setting or parsing other files).
import sublime
import sublime_plugin
# Your array, which contains the completions
arr = ["foo", "bar", "baz"]
class MyCompletionsListener(sublime_plugin.EventListener):
def on_query_completions(self, view, prefix, locations):
loc = locations[0]
# limit you completions scope
if not view.score_selector(loc, "text"):
return
completions = [(v + "\tYour Description", v) for v in arr]
return completions
OP's note: The answer works as advertised. However, the integration is so seamless that I thought for a while that something was missing. If the Python script above is on the right folder, all of the completions returned by the completions array will be suggested (depending on Sublime settings, it might be necessary to trigger the completions menu with Ctrl+Space). Also worth noting:
The completions may be None, in which case they just don't add any completion option, or an array of 2-tuples, where the first element is the description (which will be shown in the drop-down menu and trigger the completion) and the second is the value (i.e. the text that will be input if the completion is selected).
The score_selector method can be used to determine if the cursor position is within a given scope.

How to change the Sublime Text 3 StatusBar message in a command or macro (no plugin)?

addressing Sublime Text 3 users here.
I wrote a couple of macros to enable spell-check and load a specific dictionary, as I constantly swap between French and English and I wanted a simple shortcut for this (instead of browsing the menu or two successive commands in the command pallet).
My macros work as expected (french-spellcheck.sublime-macro, english-spellcheck.sublime-macro).
But I would like to display a message in the Status Bar, for instance "Switched to French" or "Switched to English" (for some time, let say 5 sec).
I looked everywhere I know and I tried for some time, but apparently there is no way to do this in a command (that could be added at the end of the macro), as the set_status internal ST3's Python API command (from Window package) is only available for plugins...
Does any one has an idea of how to display a message to the SublimeText3 StatusBar in a command/macro and not with a plugin? Thanks!
There is no built in command that invokes the API methods for doing this (at least not a documented one), so there's no way to go about this without a plugin of some sort.
That said, in order to do what you want, the following is all you would need to save into a file named e.g. set_status.py in your Packages/User folder (alongside your macros). This provides a set_status command that takes a value named value for the text to display, as mentioned in the commented out portion of your macro file.
import sublime, sublime_plugin
class SetStatusCommand(sublime_plugin.TextCommand):
def run(self, edit, value="set_status: use arg 'value' to set text"):
self.view.window ().status_message (value)
This uses a different API than the one you mention in your macro file comments; status_message does the work of displaying a message in the status bar, waiting a few seconds, and then removing it, which makes the command simple to implement.
If you wanted more control (i.e. to change the duration) you would need to modify this to invoke the API commands your macro files already mention: view.set_status() and sublime.set_timeout().

colorize text for text editor (like emacs) based on pre-defined condition?

from https://stackoverflow.com/a/21666354/433570
It's dos based solution though, can it be done for linux based system?
I'm trying to highlight stuff in my log file.
For instance, I want to highlight the line of nginx log which has slower response time than 1 sec.
** edit **
Currently I'm using hi-lock-mode
eg, I put a mark on a line that shows slow response, then use regex & hi-lock to highlight it.
I guess this is ok solution, for now.
I am wondering if there's a better solution.
hi-lock mode with user-defined function rather than regex is what I would hope for.
I would define functions, and mapping between function-color.
Then I would M-x apply [function]
def slow(line):
if ... :
return True
return False
slow: yellow,
iPhone: blue,
I think this would be useful to inspect logs..
I wonder if there's a similar functionality available out there?
Why don't you write your own major mode for your files?
A basic major mode with font-lock support is not hard to implement. There are plenty of documentation on this on the net. All you need is a syntax table (so that Emacs would know which characters start strings etc.) and some font-lock rules for syntax highlighting.
The easiest, though, is to start with an existing one, for example ini-mode, a small major mode for editing Windows-style ini files.
Unless your files have a specific file extension or otherwise follow a specific naming convention, you might want to add an entry to magic-mode-alist, which provides you with a way to recognize specific files based on the content rather than the file name.
If you would like to see your files colored in a terminal window when viewed using more or less, you can use e2ansi, a package that use Emacs to generate an ANSI version of syntax highlighted files.

Resources