Proper html attribute highlighting in Vim? - html

While I was looking for proper html tag highlighting in Vim, I found this post. But after looking at romainl's answer (and his screenshot) and html syntax file, I wonder how can I change color of = (equal sign) after attribute to match the color of an attribute without changing html tag's color?

Exploration
Here is a very useful function I've found somewhere (a long time ago, probably on the Vim Wiki) that gives you the syntax group of the word/symbol under your cursor:
function! SynStack()
if !exists("*synstack")
return
endif
echo map(synstack(line('.'), col('.')), 'synIDattr(v:val, "name")')
endfunc
Just place your cursor on the item you want to inspect and type :call SynStack() to echo the syntax group in the command-line.
If I place my cursor on the = in <div id="example"></div>, the output of SynStack() is ['htmlTag'].
With the cursor on <> I get ['htmlTag'] as well.
With the cursor on div I get ['htmlTag', 'htmlTagN', 'htmlTagName'] which means that the color of div (h1, p…) is defined via a special syntax group called htmlTagName that inherits from htmlTag.
Some alternative/custom syntax files may define other syntax groups with slightly varying name so my example is only valid for me. You'll have to play with SynStack() to get the correct syntax groups.
Reflexion
With the info we have gathered so far, it's obvious that the tag name (['htmlTagName']) can be styled independtly from the rest of the tag but it doesn't seem doable to highlight the = differently. Because it is part of the same syntax group as <>, the = will necessarilly be highlighted the same.
We have 2 possibilities:
a. <, = and > are the same colour while div is different.
b. <, div, = and > are all the same colour.
The original theme followed path a which I didn't like, so I had to customize it a little (path b) with the few lines in my answer to the previous question:
hi htmlTag guifg=#90b0d1 gui=NONE
hi htmlSpecialTagName guifg=#90b0d1 gui=NONE
hi htmlTagName guifg=#90b0d1 gui=NONE
hi htmlEndTag guifg=#90b0d1 gui=NONE
As it is, having the = coloured differently than <> is not possible. If we want to colorize the = we are going to edit the HTML syntax file and your colorscheme, cowboy style.
Action
The first step is to make a local copy of the default HTMl syntax file:
$ cp /usr/share/vim/vim73/syntax/html.vim ~/.vim/syntax/html.vim
The next step is to edit this file. We are going to perform two changes:
add the definition of the htmlEqualSign syntax group
Line 44 should be (Attention! Not thoroughly tested.):
syn match htmlEqualSign contained "="
add htmlEqualSign to the htmlTag group
Line 40 of ~/.vim/syntax/html.vim should be changed from:
syn region htmlTag start=+<[^/]+ end=+>+ contains=htmlTagN,htmlString,htmlArg,htmlValue,htmlTagError,htmlEvent,htmlCssDefinition,#htmlPreproc,#htmlArgCluster
to:
syn region htmlTag start=+<[^/]+ end=+>+ contains=htmlTagN,htmlString,htmlArg,htmlValue,htmlTagError,htmlEvent,htmlCssDefinition,#htmlPreproc,#htmlArgCluster,htmlEqualSign
The last step is to edit your colorscheme so that it colorizes = the way you want. You do that by adding this line somewhere in your colorscheme:
hi htmlEqualSign guifg=#00ff00
With the color of your choice, of course.
But I think that you want = to be the same color as id (that's not very clear from your question). For that, we are going to "link" the htmlEqualSign group to the one being used for attributes. Again, :call SynStack() is of great help: the syntax group for attributes is htmlArg so the line to add to your colorscheme would be:
hi link htmlEqualSign htmlArg

Related

Createing a Sphinx code-block, with inline text parsing

I'm trying to create a directive, that will allow me to parse links inside a Sphinx CodeBlock directive. I looked at the ParsedLiteral directive from docutils, which does something like that, only it doesn't do syntax highlighting, like CodeBlock. I tried replacing the part of CodeBlock (in sphinx/directives/code.py), which generates the literal_block:
literal: Element = nodes.literal_block(code, code)
with
text_nodes, messages = self.state.inline_text(code, self.lineno)
literal: Element = nodes.literal_block(code, "", *text_nodes)
which is what docutils ParsedLiteraldirective does, but I of course kept the rest of the Sphinx CodeBlock. This parses the code correctly, but does not apply the correct syntax highlighting, so I'm wondering where the syntax highlighting is taking place, and why it's not taking place in my modified CodeBlock directive.
I'm very confused as to why this is the case and I'm looking for some input from smarter people than me.
Syntax highlights are applied at the translation phase, see sphinx.writers.html.HTMLTranslator.visit_literal_block:
def visit_literal_block(self, node: Element) -> None:
if node.rawsource != node.astext(): # <<< LOOK AT HERE
# most probably a parsed-literal block -- don't highlight
return super().visit_literal_block(node)
lang = node.get('language', 'default')
linenos = node.get('linenos', False)
# do highlight...
Once the node's rawsource is not equal to its text, the highlight will not be applied.
In your example, code is not equal to text_nodes.as_text() obviously.
Just set literal.rawsource to literal.as_text() can fix the syntax highlight.

set auto indent on newline between auto closed HTML tag in vim (<div>|</div>) [duplicate]

I most IDEs and modern text editors (Sublime Text 3) the cursor is correctly indented after inserting a newline in between an html tag (aka 'expanding" the tag):
Before:
<div>|</div>
After pressing CR:
<div>
|
</div>
But in Vim, this is what I get:
<div>
|</div>
How can I get the same behaviour in Vim like in most other editors (see above)?
The only correct behavior of <CR> in insert mode is to break the line at the cursor.
What you want is an enhanced behavior and you need to add something to your config to get it: a mapping, a short function or a full fledged plugin.
When I started to use vim, that behavior was actually one of the first things I added to my vimrc. I've changed it many times in the past but this mapping has been quite stable for a while:
inoremap <leader><CR> <CR><C-o>==<C-o>O
I've used <leader><CR> to keep the normal behavior of <CR>.
Here is a small function that seems to do what you want:
function! Expander()
let line = getline(".")
let col = col(".")
let first = line[col-2]
let second = line[col-1]
let third = line[col]
if first ==# ">"
if second ==# "<" && third ==# "/"
return "\<CR>\<C-o>==\<C-o>O"
else
return "\<CR>"
endif
else
return "\<CR>"
endif
endfunction
inoremap <expr> <CR> Expander()
This little snippet will remap Enter in insert mode to test whether or not the cursor is between > and < and act accordingly if it is. Depending on your indent settings the \<Tab> may need to be removed.
It will not play nice with other plugins that might be also be mapping the Enter key so be aware that there is probably more work to do if you want that compatibility.
function EnterOrIndentTag()
let line = getline(".")
let col = getpos(".")[2]
let before = line[col-2]
let after = line[col-1]
if before == ">" && after == "<"
return "\<Enter>\<C-o>O\<Tab>"
endif
return "\<Enter>"
endfunction
inoremap <expr> <Enter> EnterOrIndentTag()
I have only tested the simple cases (beginning of the line, end of the line, inside and outside of ><), there are probably edge cases that this would not catch.
#RandyMorris and #romainl have posted good solutions for your exact problem.
There are some other possibilities you might be interested in if you are typing out these tags yourself: there's the ragtag.vim plugin for HTML/XML editing.
With ragtag.vim you type this to create your "before" situation (in insert mode):
div<C-X><Space>
To create your "after" situation you would instead type:
div<C-X><Enter>
So if you know beforehand that you are going to "expand" the tag, typing just the element name and the combo CtrlX followed by Enter is enough.
There are also other more advanced plugins to save keystrokes when editing HTML, such as ZenCoding.vim and Sparkup.
Since no one have mentioned it I will. There is excellent plugin that does exactly that
delemitmate

Change HTML tag in vim, but keeping the attributes (surround)

Let's say I have a tag (and cursor at *):
<h1 class="blah" id="moo">H*ello!</h1>
I want to change it to:
*<h2 class="blah" id="moo">Hello</h2>
i.e. Change the type of tag, but keep all the elements.
Using surround.vim, I could do:
cst<h2>
but that changes the HTML to:
*<h2>Hello</h2>
Is just changing the tag possible, but keeping all the attributes? Surround documentation doesn't seem to contain anything like this...
Replacing tag while keeping attributes has been added to Surround.vim
cst<p> replaces whole tag, while cst<p (without closing bracket) keeps attributes.
You can use cstt and it'll display < on the bottom and type the tag name without >
in this case, cstth2 and hit enter.
I have xml.vim plugin (https://github.com/othree/xml.vim) . If you had it too, your requirement is rather easy.
Just move cursor to tag, press <leader>c (lowercase c), then input new tagname, only tag name will be changed.
If you press <leader>C (Big C), also rename the tag/element, but also original attributes are removed.
Surround does not have this built in. You can yank the attributes and then use <c-r>" when typing out the replacement tag to bring them back, but that is a bit lame.
I propose a new mapping and function that will automate this task. The following will provide the cse mapping, aka change surrounding element. Put this in a your ~/.vimrc file or maybe ~/.vim/after/plugin/surround_change_element.vim if you feel overly orangized.
function! s:ChangeElement()
execute "normal! vat\<esc>"
call setpos('.', getpos("'<"))
let restore = #"
normal! yi>
let attributes = substitute(#", '^[^ ]*', '', '')
let #" = restore
let dounmapb = 0
if !maparg(">","c")
let dounmapb = 1
" Hide from AsNeeded
exe "cn"."oremap > <CR>"
endif
let tag = input('<', '')
if dounmapb
silent! cunmap >
endif
let tag = substitute(tag, '>*$', '', '')
exe "normal cst<" . tag . attributes . ">"
endfunction
nnoremap cse :call <SID>ChangeElement()<cr>
Note: this will shadow some cases of surroundings with e if you have any created via g:surround_101 or b:surround_101. If that is the case change the mapping form cse to something else maybe csn for change surrounding node.
EDIT
As of February 22, 2015 this answer is out of date. Please see #Wojtek Kruszewski post or :h surround-replacements for how to do this natively with surround.
In my case, I would try matchit.vim or text-object.
matchit.vim solution:
matchit.vim is included in vim.
source $VIMRUNTIME/macros/matchit.vim
and then 0l%%lr2<Ctrl-o>llr20.
text-object solution:
You can also evacuate html content to the register before replace them.
dit:.s/h1/h2/g<Ctrl-o>P0

JTextPane highlighting based on regex?

I would like to highlight words matching a regular expression in a JTextPane.
I've seen various examples but they all where very complicated with complete syntax highlighting. I just want to highlight (or set in bold) a word/sentence, is there a simple way to do that?
If the overall underlying text of what is in the JTextPane is just a regular string and not HTML:
Get the underlying document from the JTextPane.
StyledDocument sdoc = textpane.getStyledDocument()
EDITED: changed to directly calling textPane.getStyledDocument, instead of casting the result of getDocument()
Get the text of the document.
String text = sdoc.getText(0, sdoc.getLength())
Use the Pattern and Matcher classes to find the locations that match the regular expression. I assume you already know how to do that.
For every location where a match is found, highlight the start to end of the matching substring with sdoc.setCharacterAttributes or use a highlighter (see JTextPane highlight text)

Custom Vim HTML syntax

I have a script that reads an HTML file and replaces occurrences of ~%foo%~ with a value set by Perl. Something like this:
<span class="~%classname%~">~%hi_mom%~</span>
Would produce something like this in the browser:
<span class="classyclass">Hello World</span>
Right so I want to use Vim syntax highlighting to distinguish the occurrences ~%foo%~ in the HTML. By default, the HTML syntax highlighting will make an HTML element's attribute values Magenta and I want the ~%foo%~ portion to be DarkMagenta. I'm on the right track because if I comment out the tokenQuoted lines (or token lines) I get the desired results but with both matches and highlights uncommented the token highlighting overrides the tokenQuoted highlighting.
syntax match token containedin=ALLBUT,htmlString,htmlValue '\~%[^%]\+%\~'
syntax match tokenQuoted containedin=htmlString,htmlValue '\~%[^%]\+%\~'
" tokenQuoted assumes htmlString/htmlValue (:highlight String) is Magenta
highlight token term=none ctermfg=White guifg=White
highlight tokenQuoted term=none ctermfg=DarkMagenta guifg=DarkMagenta
The file I'm working in is sourced after the default html.vim is sourced via
autocmd *.html ~/.vim/syntax/html.vim in .vimrc.
The problem is that token match is not being excluded from being contained in the tokenQuoted match. To get the desired results, i.e. highlighting quoted tokens different from non quoted tokens, use the following in your syntax file.
syntax match token containedin=ALLBUT,htmlString,htmlValue,tokenQuoted '\~%[^%]\+%\~'
syntax match tokenQuoted containedin=htmlString,htmlValue '\~%[^%]\+%\~'
highlight token term=none ctermfg=White guifg=White
highlight tokenQuoted term=none ctermfg=DarkMagenta guifg=DarkMagenta
Or if it makes sense to use a syntax region rather than a match, replace the syntax match lines above with the following.
syntax region token contained start=+\~%+ end=+%\~+ containedin=ALLBUT,htmlString,tokenQuoted
syntax region tokenQuoted contained start=+\~%+ end=+%\~+ containedin=htmlString
I guess I should also mention that when I was testing this I just created the file ~/.vim/syntax/html.vim and added the above content. There was no need to add anything to my .vimrc file.