A lot of times, I have a list of initializers in some of my code, like this:
class Foo(object):
def __init__(self, data):
self.foo = data.getFoo()
self.bar = data.getBar()
self.something = data.getSomething()
As you can see, I like my code aligned like a table. In a lot of cases, the above code can be generated by scripting Vim, coming from the output of some other program (DESCRIBE "foo"; in a database for example). Unfortunately, the scripted output usually looks like this, first:
class Foo(object):
def __init__(self, data):
self.foo = data.getFoo()
self.bar = data.getBar()
self.something = data.getSomething()
So after the automatic generation of th assignment statements, I'll have to manually align all statements for the desired look.
Now: Is there a way to get vim to align those "second halves"of the statements automatically?
The tabular plugin does exactly this. You can see it in action (and learn how to use it) here.
UPDATE: I'll give a brief explanation about the plugin usage, but no explanation will be better then Drew's video, so I strongly suggest everybody to watch it.
To use the plugin just call :Tab /= and it will align all the equal signs in the file. If you want to specify which line you want to align just give it a range :5,10Tab /= or use the visual mode (v or V) to select the desired lines, press : and insert the Tabularize command, your command line will look like this: :'<,'>Tab /=.
The argument in the Tabcommand is a Regular Expression, this means you can use this command to align many things. You'll be restricted only by your Regular Expression knowledge.
Sorry for any English mistake :D
An alternative to the already mentioned Tabular plugin is the venerable Align plugin.
One naive approach would be to first make enough space around the equal signs:
:s/=/ =/
Then, block-selecting (Ctrl-V) so that all the = characters and everything that follows is selected. Yank(y) that, paste it somewhere else.
Next, un-indent the pasted lines (10< is usually sufficient) until they're aligned to the leftmost position. Then, block-select again and paste to where they were cut off.
This feels like a lot of work though, for the desired effect.
Related
Both Sublime Text 2 and VIM have a feature called marks. However, I've not been able to find a use case for it. It feels like everything you can do with it can also be done with other things, often even better.
So the question is: what is the use case of marks?
If you mean marking text lines as in vim, I use it quite a bit.
For example, if you want to quickly go look at something else, you can use ma to mark the current line as a, then go check out something else in the file, then return to where you were with a simple 'a.
Similarly, if you want to delete an unknown number of lines between your current position and somewhere else, use ma, go to that "somewhere else, and just use d'a.
There are many more things you can do with them (such as changing text between your current position and a mark), those two are just the most common ones I use (and I use them a lot).
[Edit: after reading comments I realize that the Surround plugin is adequate for my needs after all, so I'll leave this question for purely academic purposes to gain a better understanding of vimscript's inner workings]
I'd like to make adding/deleting tags, quotes, braces, and other symmetrical text structures easier to do in Vim, and I find the surround.vim plugin a little too quirky and specialized for my needs.
What I really need is more generally a "mirrored" input mode and "mirrored" deletion mode, whereby I could visually select a block of text, then type onto or delete from both ends of the selection at once. As an example workflow, I'd like to:
select the word hello
hit some keystroke combo to enter "mirror mode"
type "
my text now says "hello"
In this example I only typed one character at each end, but it's important that in step three I could have typed many characters, not just one, for instance I should be able to type <b> to produce <b>hello<b> (I still would need to manually add the / in the closing tag, which I'm OK doing).
So is this even possible in Vim? Could someone provide a broad outline of functions that would be involved in the solution? Specifically, I don't know how to intercept text as it's being inserted and then alter the location where it appears so that it's tacked onto the beginning and ending of the selection block instead of the cursor location. And ditto for deletion.
Well, the behavior you describe is exactly what Surround does:
select the word hello
hit S
type "
my text now says "hello"
The difference with what you ask is the "live updating" or "live mirroring" which I have no idea how to do. You could probably take a look at SnipMate or UltiSnips for that part.
This question already has answers here:
How do I reformat HTML code using Sublime Text 2?
(16 answers)
Closed 9 years ago.
I have a html source file containing only one line like the following:
<html><head>test</head><body>wow</body></html>
, and I want to format it as following:
<html>
<head>
test
</head>
<body>
wow
</body>
</html>
, I have used the command: Edit-> Line-> Reindent but it doesn't work.
In Sublime Text try this:
Highlight the last character in the first tag: ">"
Use Find > Quick Add Next (Command+D on Mac or Ctrl+D on PC)
You'll now have all occurrences highlighted in multiple selections, move the caret to the end of the tag and hit return to insert all the new lines you require.
Good luck
I was under the impression that Sublime provided this ability as well. When I found out that it wasn't, I had the idea of using regular expressions. Even though regex are usually considered inappropriate for parsing XML/HTML, I found this approach to be acceptable in this case. Sublime is also said to be highly customizable by plugins, so I think this would be a way.
Sublime Plugins
To be honest, I could have thought of tidy or at least suspect that there must be plugins out there dealing with your issue. Instead I ended up writing my first sublime plugin. I have only tested it with your input and expected output, which it satisfied, but it is most certainly far from working reliably. However, I post it here to share what I've learned and it's still an answer to the problem.
Opening a new buffer (Ctrl+n) and choosing the 'New Plugin...' entry in the Menu 'Tools' generously generates a little 'Hello World!' example plugin (as a Python module), which gives a great template for implementing a sublime_plugin.TextCommand subclass. A TextCommand provides access to an active buffer/currently open file. Like its relatives WindowCommand and ApplicationCommand, it is required to overwrite a run-method.
The official API Reference suggests learning by reading the example sources distributed with the Sublime builds and located in Packages/Default relative to the Sublime config path. Further examples can be found on the website. There's more on the internet.
Processing selected text
To get to a solution for your issue, we primarily need access to a View object which represents an active text buffer. Fortunately, the TextCommand subclass we are about to implement has one, and we can conveniently ask it for the currently selected regions and their selection contents, process selected text conforming our needs and replace the selected text with our preference afterwards.
To sum up the string operations: There are four regular expressions, each of which matches one of the element classes <start-tag>, <empty-tag/>, </close-tag> and text-node. Assuming that all of our markup text is covered by these, we did each line in selection into matching substrings. These are then realigned one-per-line. Having done this, we apply simple indentation by remembering to indent every line whose predecessor contains a start tag. Lines containing end tags are unindented immediately.
Using the group addressing features of Python regex, we can determine the indentation of every line and align the next one accordingly. This, with no further ado, will result in internally consistent indented markup, but with no consideration of the lines outside the selection. By extending the selection to an enclosing element, or at least complying with the indentation levels of the adjacent lines, one could easily improve the results. Its always possible to make use of the default commands.
Another thing to take care of is binding keys to the plugin command and contributing menu entries. It is probably possible somehow, and the default .sublime-menuand .sublime-commands files in Packages/Default at least give an idea. Anyway, here's some code. It has to be saved under Packages/User/whatever.py and can be called from the Sublime Python Console (Ctrl+`) like this: view.run_command('guess_indentation').
Code
import sublime
import sublime_plugin
import re
class GuessIndentationCommand(sublime_plugin.TextCommand):
def run(self, edit):
view = self.view
#view.begin_edit()
# patterns
start_tag = '<\w+(?:\s+[^>\/]+)*\s*>' # tag_start
node_patterns = [start_tag,
start_tag[:-1]+'\/\s*>', # tag_empty
'<\/\s?\w+\s?>', # tag_close
'[^>\s][^<>]*[^<\s]'] # text_node
patterns = '(?:{0})'.format('|'.join(node_patterns))
indentors = re.compile('[ \t]*({0})'.format('|'.join(node_patterns[:1])))
unindentors=re.compile('[ \t]*({0})'.format(node_patterns[2]))
# process selected text
for region in view.sel():
# if selection contains text:
if not region.empty():
selection = view.substr(region)
expanded = []
# divide selected lines into XML elements, if it contains more than one
for line in selection.split('\n'):
elements = re.findall(patterns, line)
if len(elements)>0:
expanded += elements
else:
expanded.append(line)
# indent output
indent=0
indented = []
for line in expanded:
match = unindentors.match(line)
if match:
indent = max(0, indent-1)
# append line to output, unindented if closing tag
indented.append('\t'*indent+line)
if match:
continue
# test for possible indentation candidate
# indentation applies to the NEXT line
match = indentors.match(line)
if match:
indent+=1
# replace selection with aligned output
view.replace(edit, region, '\n'.join(indented))
if its for something simple, i was able to record a macro (tools -> record macro) indenting the tags and then save it and reuse this macro. not sure if that helps any though.
Whenever I try to use a snippet (using snipMate) after a word, without a space, it does not work. So I have to hit space, type my snippet, hit tab, and then eliminate the space. Is there a better way of doing this? Is there a way to get the snipppets to work even immediately after a word? Here is what I mean:
let us say my snippet is this:
snippet test
<some code>${1}</code>${2}
typical use:
hello test[TAB]
turns into this:
hello <some code>|</code>
but if I try this:
hellotest[TAB]
it turns into this:
hellotest_____
the _ being white space. Is there a way to fix this?
Vim abbreviations can be of three types (full-id, end-id, and non-id, cp. :help abbreviations), which help solve this problem. snipMate, however, allows all non-whitespace characters for snippet names, and therefore has to rely on whitespace for separation.
You have to modify the parsing of the snippet name, in plugin/snipMate.vim, it's in the function TriggerSnippet():
let word = matchstr(getline('.'), '\S\+\%'.col('.').'c')
There's no setting to that effect if that's what you ask. You will have to look at the source and do the change there yourself, I'm afraid.
Also, it can probably seen as a limitation but it's definetely not a bug so what you are after is an improvement, not a "fix". My advice, though, is to use it as it was designed: having triggers work even if they are part of another word makes no sense at all. Spaces are the most natural way of separating ideas and words.
Consider following text file:
something
something
something = someother thing
other thing = third thing
another thing = forth thing
I want to make it look like this:
something
something
keyword something = someother thing
keyword other thing = third thing
keyword another thing = forth thing
so that, I add keyword to each line, what is contains a equals symbol in it.
Can I do this with global command, or how do you recommend I should do this?
:g/=/s/^/keyword /
or
:g/=/normal ikeyword
Note the space after "keyword"
For this type of problem, it's also quite common to use a solution like:
:%!sed '/=/s/^/keyword /'
I'm not quite sure what you're attempting to accomplish. Your title suggests a common pattern, but I don't see one in your example. So I'll show you both.
Making Changes Among Things With A Common Pattern
You can do search and replace with the following:
:s/<regex you are searching for>/<string to replace with>/g
s/pattern/replacement/ does search & replace, and the extra g will propogate the changes
Multi-Line Edit
Vim also lets you edit multiple lines at once. Say you want to edit the following three lines:
something = someother thing
other thing = third thing
another thing = fourth thing
Put your cursor on the s at the first something line.
Press <ctrl>-v outside of insert mode to go into Visual mode.`
Scroll down to the a on the bottom line. All three starting characters of all 3 lines should be highlighted.
Press A to append or I to enter directly into insert mode and start typing. When you hit escape your changes should reflect! You can also do other commands like y and d, etc.