Select or Highlight all instances of a word type or color in Sublime Text 4 - sublimetext3

Note: I am not trying to select all instances of a single word.
I can not find a way to select all instances of a word type, similarly how different words are colored according to the format rules from the file type you have.
Here is an image of some sample code of a SQL file.
For example, I would like to Highlight all instances of this reddish pink color, or the baby blue colored words in the whole file. So that way I can capitalize them or copy them or what have you.

From the Tools menu -> Developer -> New Plugin...
Replace the template with the following:
import sublime
import sublime_plugin
class SelectByScopeSelectorCommand(sublime_plugin.TextCommand):
def run(self, edit, scope_selector=None, last_scope_only=True, auto_select=False):
if not scope_selector:
scope_at_first_caret = self.view.scope_name(self.view.sel()[0].a)
if last_scope_only:
scope_at_first_caret = scope_at_first_caret.split()[-1]
if auto_select:
scope_selector = scope_at_first_caret
else:
self.view.window().show_input_panel('Scope Selector', scope_at_first_caret, lambda value: self.view.run_command('select_by_scope_selector', { 'scope_selector': value }), None, None)
return
regions = self.view.find_by_selector(scope_selector)
if regions:
self.view.sel().clear()
self.view.sel().add_all(regions)
self.view.show_at_center(self.view.sel()[0])
else:
self.view.window().status_message('Unable to find anything matching selector "' + scope_selector + '"')
Save it, in the folder ST recommends, as something like select_by_selector.py (the filename doesn't matter too much, but the extension is important).
Then, in your User keybindings, you can add something like:
{ "keys": ["alt+;"], "command": "select_by_scope_selector", "args": { "last_scope_only": true, "auto_select": true } },
Then, pressing Alt+; with the selection caret somewhere in SELECT, it will automatically select all other words in the buffer with the same scope, like DELETE, UPDATE, INSERT etc. Or on INT, it could select all INT, CHAR etc.
You may notice that the "types" you referred to in your question are called scopes in ST parlance. Note that colors don't necessarily have a one to one mapping with scopes depending on your color scheme, so it may select more or less than you expect it to.
You can play around with the keybinding, by removing all arguments for example, to see what effect it has and customize which scopes are being searched for. You can also add it to a menu or the command palette, if that is more to your liking. I suggest to read the ST docs for more info.

Related

Move Cursor Immediately Before a Character on a Line in Vim

Say I have the following:
text function(contents) text
and I wanted it to be
text function() text
Placing the cursor right after the opening parenthesis, I thought the following command would work df); however, what I ended up with was the following
text function( text
So I would need someway to specify that I want the character just before the closing parenthesis, but I'm not sure how to do that. There may also be a better way to do this.
What would be the best way to go about this?
You were close! You need dt) as in delete till )
The f motion places the cursor on the ) (remember it like find)
As for the 'best' way to do it, there is at least a more general way: if the
cursor were somewhere in the middle of the ( and ) (or on one of them), you
can do di) (or equivalently di() to delete inside )
If you do da) (or equivalently da() to delete around ), you would
delete the stuff in between and including the brackets.
The same goes for di[, di{, di<, di', di" etc. Using these so-called
text objects, as opposed to the d{motion} way, has the advantage that you can
repeat the edit on other pairs of brackets/quotes without the cursor needing to
be in precisely the same place - it just needs to be on or in between them.
In the following you could position the cursor on e.g. the 'i' of 'initial' in
the first line, do di) to delete the words 'some initial text', then move the
cursor to the 'e' in 'more' in the second line and just do . to also delete
the words 'some more text'):
(some initial text)
(some more text)
This way also works when the brackets (or quotes) are on different lines. For
example, with the cursor somewhere between the {}, doing di} will change
this:
function( args ) {
body of function
}
to this:
function( args ) {
}

formatting text output in terminals

I'm currently writing a command line tool for myself, that needs to print some information on the terminal. I'm a little annoyed of the whole formatting. Here is my example.
formatter = logging.Formatter(fmt = '%(message)s')
console_logger = logging.getLogger("console_logger")
console_logger.setLevel(logging.DEBUG)
console_logger_handler = logging.StreamHandler()
console_logger_handler.setFormatter(formatter)
console_logger.addHandler(console_logger_handler)
console_logger.propagate = False
here goes some further code and then I have the printing function
for element in open_orders:
console_logger.info("Type: {}, Rate: {}, amount: {}, state: {}, pair: {}/{}, creation: {}, id: {}".format(element.type,
element.rate,
element.amount,
element.state,
element.currency_pair.get_base_currency().upper(),
element.currency_pair.get_quote_currency().upper(),
creation_time,
element.order_id))
I rather would like to have this as a column where the output is aligned at the colon. after each element a line of underscores or minusses would be nice as well, this should respect terminal width. I know this can be hardcoded in some manner, but isn't there a better way? Some kind of templating engine that can handle multiline output?
EDIT:
So here is an example:
Type : buy
Rate : 1234
amount : 1
state : active
pair : usd/eur
creation : 2017.12.12
I know this can be printed line by line with format but I need to determine the length of the longest string on my own and I was wondering if there isn a framework or something more elegant doing this for me.
id : 123456
Use format, add with your data :
for element in open_orders:
console_logger.info("Type: {:25s}, Rate: {:25s}, amount: {:07.2f}, state: {:25s}, pair: {:25s}/{:25s}, creation: {:25s}, id: {:25s}".format(element.type,
element.rate,
element.amount,
element.state,
element.currency_pair.get_base_currency().upper(),
element.currency_pair.get_quote_currency().upper(),
creation_time,
element.order_id))
You can also visit this site : https://pyformat.info/
In addition, you could try to use Colorama.
You have to install it, tipically, from pypi.
It allows you to handle cursor positioning, so you can control in which position at the screen (terminal) you want to print data, using "coordinates". Also, you can apply colors to text, which could give you a cleaner and prettier look if you want to.
So what I finally found which helps a lot at least in case of lists and formatting of them is this
terminaltable

Sublime Text: select/edit all occurrences of variable *scoped to function*

Sublime provides ability to:
select/edit all occurrences of a variable (Quick Find All; alt+F3 on Windows)
select each occurrence one-by-one and then edit the summed total (Quick Add Next; ctrl+d on Windows)
What I want:
select/edit all occurrences within a function's scope
note: I've read this related link (Sublime Text: Select all instances of a variable and edit variable name) and didn't see an answer to how editing might be restricted to function scope.
You can create a fairly simple plugin to do this, making use of Quick Find All, and then just removing any selections that are not inside the current function.
From the Tools menu -> Developer -> New Plugin...
Replace the contents of the new tab with the following:
import sublime
import sublime_plugin
class SelectWordInFunctionCommand(sublime_plugin.TextCommand):
def run(self, edit):
view = self.view
prev_sel = [sel for sel in view.sel()]
function_region = next((region for region in view.find_by_selector('meta.function') if region.contains(view.sel()[0])), None)
if function_region:
#word = view.expand_by_class(view.sel()[0].begin(), sublime.CLASS_WORD_START + sublime.CLASS_WORD_END)
view.window().run_command('find_all_under')
sel = [sel for sel in view.sel() if function_region.contains(sel)]
view.sel().clear()
view.sel().add_all(sel if any(sel) else prev_sel)
else:
view.window().status_message('Not inside a function')
instead of using the find_all_under command, use select_word_in_function - you can create a keybinding to do this only when inside a function definition:
{ "keys": ["alt+f3"], "command": "select_word_in_function", "context":
[
{ "key": "selector", "operator": "equal", "operand": "meta.function", "match_all": true },
]
},
Disclaimer: this definitely works with PHP in ST build 3142 and other syntaxes that scope the whole function, but a different approach to detect where the function starts and ends may need to be used for other syntaxes that can't/don't behave this way.

vim macro until pattern is matched

I have an array of states that no one is going to have to modify often, so I want to remove the white space.
I tried the following keystrokes as there are some whitespace characters between the commas in the array and the endlines:
q a /, ENTER FORWARD v /\n ENTER d
Unfortunately, whomever formatted this neglected to place any whitespace after 'Montana', so when I run the macro 51#a, it breaks after 27 iterations.
How can I have a macro only run a pattern if \s is matched, or better yet, how can I run a macro until it recognizes ); (end of array).
EDIT: Here is an example. Note the two white space characters after all entries except keys MT,NE,NV and NH.
$state_list = array('AL'=>"Alabama",
'AK'=>"Alaska",
'AZ'=>"Arizona",
'AR'=>"Arkansas",
'CA'=>"California",
'CO'=>"Colorado",
'CT'=>"Connecticut",
'DE'=>"Delaware",
'DC'=>"District Of Columbia",
'FL'=>"Florida",
'GA'=>"Georgia",
'HI'=>"Hawaii",
'ID'=>"Idaho",
'IL'=>"Illinois",
'IN'=>"Indiana",
'IA'=>"Iowa",
'KS'=>"Kansas",
'KY'=>"Kentucky",
'LA'=>"Louisiana",
'ME'=>"Maine",
'MD'=>"Maryland",
'MA'=>"Massachusetts",
'MI'=>"Michigan",
'MN'=>"Minnesota",
'MS'=>"Mississippi",
'MO'=>"Missouri",
'MT'=>"Montana",
'NE'=>"Nebraska",
'NV'=>"Nevada",
'NH'=>"New Hampshire",
'NJ'=>"New Jersey",
'NM'=>"New Mexico",
'NY'=>"New York",
'NC'=>"North Carolina",
'ND'=>"North Dakota",
'OH'=>"Ohio",
'OK'=>"Oklahoma",
'OR'=>"Oregon",
'PA'=>"Pennsylvania",
'RI'=>"Rhode Island",
'SC'=>"South Carolina",
'SD'=>"South Dakota",
'TN'=>"Tennessee",
'TX'=>"Texas",
'UT'=>"Utah",
'VT'=>"Vermont",
'VA'=>"Virginia",
'WA'=>"Washington",
'WV'=>"West Virginia",
'WI'=>"Wisconsin",
'WY'=>"Wyoming"
);
To:
$state_list=array('AL'=>"Alabama",'AK'=>"Alaska",'AZ'=>"Arizona",'AR'=>"Arkansas",'CA'=>"California",'CO'=>"Colorado",'CT'=>"Connecticut",'DE'=>"Delaware",'DC'=>"District Of Columbia",'FL'=>"Florida",'GA'=>"Georgia",'HI'=>"Hawaii",'ID'=>"Idaho",'IL'=>"Illinois",'IN'=>"Indiana",'IA'=>"Iowa",'KS'=>"Kansas",'KY'=>"Kentucky",'LA'=>"Louisiana",'ME'=>"Maine",'MD'=>"Maryland",'MA'=>"Massachusetts",'MI'=>"Michigan",'MN'=>"Minnesota",'MS'=>"Mississippi",'MO'=>"Missouri",'MT'=>"Montana",'NE'=>"Nebraska",'NV'=>"Nevada",'NH'=>"New Hampshire",'NJ'=>"New Jersey",'NM'=>"New Mexico",'NY'=>"New York",'NC'=>"North Carolina",'ND'=>"North Dakota",'OH'=>"Ohio",'OK'=>"Oklahoma",'OR'=>"Oregon",'PA'=>"Pennsylvania",'RI'=>"Rhode Island",'SC'=>"South Carolina",'SD'=>"South Dakota",'TN'=>"Tennessee",'TX'=>"Texas",'UT'=>"Utah",'VT'=>"Vermont",'VA'=>"Virginia",'WA'=>"Washington",'WV'=>"West Virginia",'WI'=>"Wisconsin",'WY'=>"Wyoming");
EDIT:
Just googled vim macro until pattern matched, and came across my own question. I have a better example now:
namespace A{
class a{}
class a{}
}
namespace B{
class b{}
class b{}
class b{}
}
Needs to become:
namespace A{
class Aa{}
class Aa{}
}
namespace B{
class Bb{}
class Bb{}
class Bb{}
}
This cannot be solved with the previously accepted answer.
Honestly the easiest answer would be to join the lines.
If you visual select the entire region and just press J (or feed the range to :join) all of the lines will end up on one line. (There may be excess whitespace in-between elements but thats easier to fix then trying to write the macro).
If you then want to remove the excess whitespace you could run
:s/,\s\+/,/g
on the joined line.
Take a look at :h J and :h :join
First of all, you can easily remove all trailing whitespace with one command:
:%s/\s\+$//e
That will work on every line of the file. If you want to do it only on this fragment of code, you can specify different range (instead of %, which is whole file). For example, you can pass line numbers (1 to 51):
:1,51s/\s\+$//e
or first visually select, and then run command removing whitespace (you have to be on the first line starting this sequence):
V/)<CR>:s/\s\+$//e
If you really want to use macro, you can slightly tweak (and simplify) your macro:
qa0f,lDq
and then run it on every line at once by first of all visually selecting all of them (again, start on line you want, I won't put gg here because it might be just part of the file):
V/)<CR>:normal #q
This will play the macro over every selected line, up to the line with ).
I hope it helps :)

Why Text cursor coordinates are not updated correctly?

To create a simple line-column counter for my text editor, I decided to simply use the index function of the tkinter.Text widget. In fact, the index function returns a string representing the line and column of the coordinates passed as argument to it.
Specifically, I am using cursor_pos = text.index(tkinter.INSERT) to get the index of the cursor, since, from the effbot website on tkinter.INSERT:
tkinter.INSERT corresponds to the insertion cursor.
The problem is that tkinter.INSERT seems to give me the last cursor position until I move the cursor with the arrows (for example).
This is the function that handles the count of the lines and columns:
def on_key_pressed(self, event=None):
"""Docs """
if self.tpane is not None:
print(self.lines, self.columns)
self.tpane.update()
cursor_pos = self.tpane._tabs[self.tpane.selected()].text.index(tkinter.INSERT)
self.lines = int(cursor_pos.split('.')[0])
self.columns = int(cursor_pos.split('.')[1])
print(self.lines, self.columns)
self.line_c.config(text='Lines: ' + str(self.lines))
self.col_c.config(text='Columns: ' + str(self.columns))
self.update()
I don't know if you can understand the situation... When I first type a letter on the editor, the self.columns variable does not update to 1 (remains 0) until I write the second letter, where it updates to 1, and so on. But there's a trick to make it update without writing a new letter. Once written the first letter, if I move the cursor with the arrows, it updates the self.columns to actually 1.
Another problem is when I try to delete a existent character. For example, if I have 3 characters (and suppose I have self.columns to 3), and I press delete, self.columns update inexplicably to 4, and if I try to remove another character, at this point, it updates to 3.
This problems exists also for the self.lines in the on_key_pressed event handler. I am not sure if this is supposed to happen, and if yes, then I am missing something...
This happens because your custom binding fire before the built-in bindings, and it is the built-in bindings that actually modify the widget and change the cursor position.
You can change the order by leveraging bindtags. For more information see this question: Basic query regarding bindtags in tkinter
For an example of how to change the bindtags, see this answer: https://stackoverflow.com/a/3513906/7432
If you don't want to deal with bindtags, you can bind to <KeyRelease>. Built-in bindings happen on a key press, so the release binding will always fire after the widget has been updated.

Resources