From: Dasn C. <Da...@my...> - 2003-08-25 22:11:41
|
I happened to find this plugin file which can help us format multibyte text= . I hope it can be useful. "=09=09=09=09=09=09=09=09 Version 1.5 " format.vim -=09Format multibyte text, for tha languages, which can split "=09=09line anywhere, unless prohibited. (for Vim 6.0 alpha) " " Last Change:=09 12-Jan-2002. " Maintainer:=09 Muraoka Taro <ko...@tk...> " Practised By:=09 Takuhiro Nishioka <tak...@su...> " Base Idea:=09 Muraoka Taro <ko...@tk...> " Copyright:=09 Public Domain " Modified:=09 Edward G.J. Lee <ed...@sp...> 2002.02.11 " =D7=D4=D0=D0=B8=FC=B8=C4=CE=AA cp950 =D2=D4=CA=CA=BA=CF=B7=B1=CC=E5=D6=D0= =CE=C4 scriptencoding cp950 " function Format(start_line_number, end_line_number) "=20 " Format() will allow format multibyte text. In some of East Asian " languages, the line can break anywhere, unless prohibited. Original Vim'= s " "gq" format command doesn't allow to break line at the midst of word. " This function split line at each multibyte character. And it can handle " prohibited line break rules. " " This function is following Vim's "gq" command. But there will be lack of " something. if exists('plugin_format_disable') finish endif "--------------------------------------------------------------------------= - "=09=09=09=09 Options " " "format_command" " " Specifies the format command that format lines to the width the " 'textwidth' option specifies. The "Q" command formerly did this, so if yo= u " still want to use "Q", set this to "Q" " "let format_command =3D "Q" if !exists('format_command') let format_command =3D "gq" endif " " "format_join_spaces" " " Delete a space , when joining lines, according to the following rules. " This rule is also applied to "J" command " 1=09line end with AND next line start with a multibyte char " 2=09line end with OR next line start with a multibyte char " 3=09same with original join command " if !exists("g:format_join_spaces") let g:format_join_spaces =3D 1 endif " " "format_follow_taboo_rule" " " Move to a point that will not break forbidden line break rules. If you " don't want to do this, set this to "0". " if !exists("g:format_follow_taboo_rule") let g:format_follow_taboo_rule =3D 1 endif " " "format_allow_over_tw" " " The width that can over 'textwidth'. This variable is used for taboo rule= . " if !exists("g:format_allow_over_tw") let g:format_allow_over_tw =3D 2 endif " " "format_indent_sensitive" " " When the indentation changes, it's the end of a paragraph. Note that if " this option is set, second indentation is disabled. " if !exists("g:format_indent_sensitive") let g:format_indent_sensitive =3D 0 endif "--------------------------------------------------------------------------= - "=09=09=09=09 Sub Options " " "g:format_no_begin" " " This option is space-separated list of characters, that are forbidden to " be at beginning of line. Add two spaces for ASCII characters. See also " TabooRuleMatch() let g:format_no_begin =3D "! , . ? ) ] } - _ ~ : ; =A3=A1 =A3= =AC =A1=A3 =A3=BF =A3=A9 =A3=BA =A3=BB " " " "g:format_no_end" " " This option is space-separated list of characters, that are forbidden to " be at end of line. Add two spaces for ASCII characters. See also " TabooRuleMatch() " let g:format_no_end =3D "( [ { " " " For Japanese. There are encoding name aliases, so we cannot directly " compare option 'encoding' with locale name (ex: 'japan'). " "let s:save_encoding =3D &encoding "let &encoding =3D 'japan' "if &encoding =3D=3D s:save_encoding " let no_b =3D '' " let no_b =3D no_b . "?? ?? ?f ?h ?? ?? ?? ?? ?A ?B ?X ?r ?t ?v ?x ?z ?l = " " let no_b =3D no_b . "?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?J ?K ?T ?U " " let no_b =3D no_b . "?@ ?B ?D ?F ?H ?b ?? ?? ?? ?? ?? ?? " " let no_b =3D no_b . "?E ?[ ?R ?S ?I ?? ?j ?C ?D ?F ?G ?H ?n ?p ?c ?` " " let no_e =3D '' " let no_e =3D no_e . "?? ?e ?g ?q ?s ?u ?w ?y ?k ?? ?i ?m ?o ?? " " let g:format_no_begin =3D g:format_no_begin . no_b " let g:format_no_end =3D g:format_no_end . no_e " unlet no_b no_e "endif "let &encoding =3D s:save_encoding "unlet s:save_encoding " " "s:format_motion_list" " " Specifiles the motion command that could follow "format_command". These " are pairs of two letters. Note that not all motion commands can be " specified here. Use visual mode for other motions. " let m_list =3D "apawaWasa]a[a)a(aba>a}a{aB" let m_list =3D m_list . "ipiwiWisi]i[i)i(ibi>i}i{iB" let m_list =3D m_list . "gqq " let m_list =3D m_list . "h j k l 0 ^ $ ; , - + w W e E b B " let m_list =3D m_list . "( ) { } n N % H M L G / ? " let m_list =3D m_list . "gjgkggg0g^gmgegEg$]][[][[[[]''``" let m_list =3D m_list . "'[`[']`]'<`<'>`>'\"`\"" let m_list =3D m_list . "[([{])]}]m]M[m[M[#]#[*[/" let m_list =3D m_list . "'a'b'c'd'e'f'g'h'i'j'k'l'm'n'o'p'q'r's't'u'v'w'x'y= 'z" let m_list =3D m_list . "`a`b`c`d`e`f`g`h`i`j`k`l`m`n`o`p`q`r`s`t`u`v`w`x`y= `z" let m_list =3D m_list . "2j3j4j5j6j7j8j9j" let m_list =3D m_list . "2k3k4k5k6k7k8k9k" let m_list =3D m_list . "2H3H4H5H6H7H8H9H" let m_list =3D m_list . "2L3L4L5L6L7L8L9L" let s:format_motion_list =3D m_list unlet m_list "--------------------------------------------------------------------------= - " " DoMappings() " Do mappings. " function! DoMappings() " Normal mode mappings. let length =3D strlen(s:format_motion_list) let i =3D 0 while i <=3D length - 2 let motion =3D strpart(s:format_motion_list, i, 2) let motion =3D substitute(motion, " $", "", "") execute "nmap <silent> " . g:format_command . motion . " :call " . "<SI= D>FormatWorkhorse(\"" . motion . "\")<CR>" let i =3D i + 2 endwhile " Visual mode mapping. execute "vmap <silent> ".g:format_command." <ESC>:call"." <SID>Format(lin= e(\"'<\"), line(\"'>\"))<CR>" " Change "J" to follow "g:format_join_spaces" nmap <silent> J :call <SID>DoRangeJoin("")<CR> vmap <silent> J <ESC>:call <SID>DoJoinRange(line("'<"), line("'>"))<CR> endfunction " " FormatWorkhorse(motion) " Select the area that moves over, then pass the start and end line numbe= r " of the area to Format() " function! s:FormatWorkhorse(motion) if a:motion =3D=3D "gq" || a:motion =3D=3D "q" execute "normal! V\<ESC>" elseif a:motion =3D=3D "/" || a:motion =3D=3D "?" execute "let pattern =3D input(\"" . a:motion . "\")" execute "normal! v" . a:motion . pattern . "\<CR>\<ESC>" else execute "normal! v" . a:motion . "\<ESC>" endif call s:Format(line("'<"), line("'>")) endfunction " " Format(start_lnum, end_lnum) " Format the area from the start line number to the end line number. " function! s:Format(start_lnum, end_lnum) let count_nr =3D a:end_lnum - a:start_lnum + 1 let advance =3D 1 " current line is the start of a paragraph. let first_par_line =3D 1 " the second indent let second_indent =3D "default" " Check 2 in the formatoptions let do_second_indent =3D s:HasFormatOptions('2') let showcmd_save =3D &showcmd set noshowcmd let wrap_save =3D &wrap set nowrap let lazyredraw_save =3D &lazyredraw set lazyredraw " Set cursor to the start line number. call s:SetCursor(a:start_lnum) " Get info about the previous and current line. if a:start_lnum =3D=3D 1 " current line is not part of paragraph let is_not_par =3D 1 else normal! k " the commet leader of current line let leader =3D s:GetLeader() let is_not_par =3D s:FmtCheckPar(leader) normal! j endif " the commet leader of next line let next_leader =3D s:GetLeader() " next line not part of paragraph let next_is_not_par =3D s:FmtCheckPar(next_leader) " at end of paragraph let is_end_par =3D is_not_par || next_is_not_par " operation top let op_top =3D 1 while count_nr > 0 " Advance to next paragraph. if advance if op_top =09let op_top =3D 0 else =09normal! j endif let leader =3D next_leader let is_not_par =3D next_is_not_par " previous line is end of paragraph let prev_is_end_par =3D is_end_par endif " The last line to be formatted. if count_nr =3D=3D 1 let next_leader =3D "" let next_is_not_par =3D 1 else normal! j let next_leader =3D s:GetLeader() let next_is_not_par =3D s:FmtCheckPar(next_leader) normal! k endif let advance =3D 1 let is_end_par =3D is_not_par || next_is_not_par " Skip lines that are not in a paragraph. if !is_not_par " For the first line of a paragraph, check indent of second line. " Don't do this for comments and empty lines. if first_par_line =09 \&& do_second_indent =09 \&& prev_is_end_par =09 \&& leader =3D~ "^\\s*$" =09 \&& next_leader =3D~ "^\\s*$" =09 \&& getline(line(".") + 1) !~ "^$" =09let second_indent =3D next_leader endif " When the comment leader changes, it's the end of the paragraph if !s:SameLeader(leader, next_leader) =09let is_end_par =3D 1 endif " If we have got to the end of a paragraph, format it. if is_end_par =09" do the formatting =09call s:FormatLine(second_indent) =09let second_indent =3D "default" =09let first_par_line =3D 1 endif " When still in same paragraph, join the lines together. if !is_end_par =09let advance =3D 0 =09" join current line and next line without the comment leader =09call s:DoJoin(next_leader) =09let first_par_line =3D 0 endif endif let count_nr =3D count_nr - 1 endwhile if wrap_save set wrap endif if !lazyredraw_save set nolazyredraw endif if showcmd_save set showcmd endif endfunction " " FormatLine(second_indent) " Format currentline. " function! s:FormatLine(second_indent) " check textwidth if &textwidth =3D=3D 0 let textwidth =3D 76 else let textwidth =3D &textwidth endif let do_second_indent =3D s:HasFormatOptions("2") let fo_do_comments =3D s:HasFormatOptions("q") let second_indent =3D a:second_indent " save the original option's value let formatoptions_save =3D &formatoptions let iskeyword_save =3D &iskeyword let leader_width =3D s:GetLeader("get_leader_width") " When fo_do_comments is TRUE, set formatoptions value so that the commen= t " leader is set for next line. if fo_do_comments set formatoptions+=3Dr else set formatoptions-=3Dr endif " Set iskeyword option value to every printable ascii characters, so that " "w" can stop at only multibyte-ascii boundary or white space. set iskeyword=3D"!-~" call s:SetCursor(line("."), textwidth) while s:GetWidth() > virtcol(".") let finish_format =3D 0 let force_fold =3D 0 let do_insert =3D 0 let max_width =3D virtcol(".") + g:format_allow_over_tw let ch =3D s:GetCharUnderCursor() normal! l let next_ch =3D s:GetCharUnderCursor() normal! h " English word folding if ch =3D~ "[!-~]\\{1}" && next_ch =3D~ "[!-~]\\{1}" call s:MoveToWordBegin() if virtcol(".") - 1 > leader_width =09" move to previous word end =09normal! ge endif endif " Skip white spaces if ch =3D~ "\\s" while ch =3D~ "\\s" && virtcol(".") - 1 > leader_width =09normal! h =09let ch =3D s:GetCharUnderCursor() endwhile let force_fold =3D 1 endif if virtcol(".") - 1 <=3D leader_width call s:MoveToFirstWordEnd(leader_width) let force_fold =3D 1 if s:GetWidth() =3D=3D virtcol(".") =09let finish_format =3D 1 endif endif " Taboo rule if !finish_format && !force_fold && g:format_follow_taboo_rule normal! l let next_ch =3D s:GetCharUnderCursor() normal! h if s:TabooRuleMatch(g:format_no_begin, next_ch) =09normal! l =09while s:TabooRuleMatch(g:format_no_begin, next_ch) =09 " if cursor is at the line end, break. =09 if s:GetWidth() =3D=3D virtcol(".") =09 let finish_format =3D 1 =09 break =09 endif =09 normal! l =09 let next_ch =3D s:GetCharUnderCursor() =09endwhile =09if !finish_format =09 normal! h =09endif endif let ch =3D s:GetCharUnderCursor() if virtcol(".") > max_width =09let finish_format =3D 0 =09while s:TabooRuleMatch(g:format_no_begin, ch) =09 \&& virtcol(".") - 1 > leader_width =09 normal! h =09 let ch =3D s:GetCharUnderCursor() =09endwhile =09if ch =3D~ "[!-~]\\{1}" =09 call s:MoveToWordBegin() =09 if virtcol(".") - 1 > leader_width =09 normal! ge =09 else =09 call s:MoveToFirstWordEnd(leader_width) =09 let force_fold =3D 1 =09 endif =09else =09 let do_insert =3D 1 =09endif endif let ch =3D s:GetCharUnderCursor() if s:TabooRuleMatch(g:format_no_end, ch) && !force_fold =09let do_insert =3D 0 =09while s:TabooRuleMatch(g:format_no_end, ch) =09 \&& virtcol(".") -1 > leader_width =09 normal! h =09 let ch =3D s:GetCharUnderCursor() =09endwhile =09if virtcol(".") -1 <=3D leader_width =09 call s:MoveToFirstWordEnd(leader_width) =09endif endif endif if finish_format break endif if do_insert call s:InsertNewLine() else call s:AppendNewLine() endif if do_second_indent && second_indent !=3D "default" call setline(line(".") =09 \, second_indent . substitute(getline("."), "^\\s*", "", "")) let do_second_indent =3D 0 if strlen(second_indent) > 0 =09normal! h endif endif if virtcol(".") =3D=3D 1 let leader_width =3D 0 else let leader_width =3D virtcol(".") endif call s:SetCursor(line("."), textwidth) endwhile execute "set formatoptions=3D" . formatoptions_save execute "set iskeyword=3D" . iskeyword_save endfunction " " GetLeader(...) " Get the comment leader string from current line. If argument " is specified, then return the comment leader width. Note that " returned comment leader and the current line's comment leader is " not always same. " function! s:GetLeader(...) if !s:HasFormatOptions('q') if a:0 =3D=3D 1 return 0 endif return "" endif let col_save =3D virtcol(".") let formatoptions_save =3D &formatoptions let autoindent_save =3D &autoindent let cindent_save =3D &cindent let smartindent_save =3D &smartindent set formatoptions+=3Do set autoindent set nocindent set nosmartindent execute "normal! ox\<ESC>\"_x" if a:0 =3D=3D 1 if getline(".") =3D~ "^$" let leader_width =3D 0 else let leader_width =3D virtcol(".") endif endif let leader =3D getline(".") if line(".") =3D=3D line("$") normal! "_dd else normal! "_ddk endif execute "set formatoptions=3D" . formatoptions_save if !autoindent_save set noautoindent endif if cindent_save set cindent endif if smartindent_save set smartindent endif execute "normal! " . col_save . "|" if a:0 =3D=3D 1 return leader_width else return leader endif endfunction " " FmtCheckPar(leader) " Blank lines, lines containing only white space or the comment leader, " are left untouched by the formatting. The function returns true in this " case. " function! s:FmtCheckPar(leader) let three_start =3D substitute(&com, '.*s[^:]*:\([^,]*\),.*', '\1', '') let three_end =3D substitute(&com, '.*e[^:]*:\([^,]*\),.*', '\1', '') let line =3D substitute(getline("."), "\\s*$", "", "") let line =3D substitute(line, "^\\s*", "", "") let leader =3D substitute(a:leader, "\\s*$", "", "") let leader =3D substitute(leader, "^\\s*", "", "") if line =3D=3D three_start || line =3D=3D three_end return 1 endif return line =3D=3D leader endfunction " " SameLeader(leader1, leader2) " Return true if the two comment leaders given are the same. White-space = is " ignored. " function! s:SameLeader(leader1, leader2) if g:format_indent_sensitive return a:leader1 =3D=3D a:leader2 else return substitute(a:leader1, "\\s\\+$", "", "") =09\=3D=3D substitute(a:leader2, "\\s\\+$", "", "") endif endfunction " " SetCursor(lnum, width) " Set cursor to the line number, then move the cursor to within the width " and the most right virtual column. " function! s:SetCursor(lnum, ...) execute a:lnum if a:0 =3D=3D 1 execute "normal! " . a:1 . "|" if a:1 > 2 && virtcol(".") > a:1 normal! h endif endif endfunction " " HasFormatOptions(x) " Return true if format option 'x' is in effect. Take care of no " formatting when 'paste' is set. " function! s:HasFormatOptions(x) if &paste \|| (a:x =3D=3D "2" && !&autoindent) \|| (a:x =3D=3D "2" && g:format_indent_sensitive) return 0 endif return &formatoptions =3D~ a:x endfunction " " DoRangeJoin(next_leader) " DoJoin driver, able to support range. " function! s:DoRangeJoin(next_leader) range if count > 2 let repeat =3D count - 1 else let repeat =3D 1 endif while repeat call s:DoJoin(a:next_leader) let repeat =3D repeat - 1 endwhile endfunction " " DoJoin(next_leader) " Join line and next line ,according to g:format_join_spaces. The comment " leader will be removed. " function! s:DoJoin(next_leader) if line(".") =3D=3D line("$") return endif let showcmd_save =3D &showcmd set noshowcmd let wrap_save =3D &wrap set nowrap let lazyredraw_save =3D &lazyredraw set lazyredraw normal! $ let end_char =3D s:GetCharUnderCursor() if s:HasFormatOptions("q") && a:next_leader !=3D "" let next_leader =3D escape(a:next_leader, '^.*\$~[]') let next_leader =3D "^" . substitute(next_leader, "\\s*$", "", "") normal! j0 if getline(".") =3D~ next_leader call setline(line("."), substitute(getline("."), next_leader, "", "")= ) else let leader_width =3D s:GetLeader("get_leader_width") let i =3D leader_width + 1 execute "normal! 0\"_d" . i . "|" endif normal! k endif normal! J if s:GetWidth() > virtcol(".") && s:GetCharUnderCursor() =3D=3D " " normal! l let begin_char =3D s:GetCharUnderCursor() normal! h if g:format_join_spaces =3D=3D 1 =09\&& (strlen(end_char) > 1 && strlen(begin_char) > 1) normal! "_x elseif g:format_join_spaces =3D=3D 2 =09\&& (strlen(end_char) > 1 || strlen(begin_char) > 1) normal! "_x endif endif if wrap_save set wrap endif if !lazyredraw_save set nolazyredraw endif if showcmd_save set showcmd endif endfunction " " DoJoinRange(start_lnum, end_lnum) " Join lines from start_lnum to end_lnum, according to the " "$fomrat_join_spaces" " function! s:DoJoinRange(start_lnum, end_lnum) let count_nr =3D a:end_lnum - a:start_lnum call s:SetCursor(a:start_lnum) while count_nr > 0 call s:DoJoin("") let count_nr =3D count_nr - 1 endwhile endfunction " " GetWidth() " Return the current line width. If the line is empty returns 0. Note tha= t " if the character at the line end is a multibyte character, this returns " real width minus 1, same as virtcol(). " function! s:GetWidth() return virtcol("$") - 1 endfunction " " GetCharUnderCursor() " Get (multibyte) character under current cursor. " function! s:GetCharUnderCursor() let str =3D getline(".") let idx =3D col(".") - 1 let ch =3D str[idx] if char2nr(ch) >=3D 128 return strpart(str, idx, 2) else return ch endif endfunction " " AppendNewLine() " Insert newline after cursor. " function! s:AppendNewLine() execute "normal! a\<CR>\<ESC>" endfunction " " InsertNewLine() " Insert newline before cursor. " function! s:InsertNewLine() execute "normal! i\<CR>\<ESC>" endfunction " " MoveToWordEnd() " Move to the word end. " function! s:MoveToWordEnd() if line(".") =3D=3D 1 normal! wge else normal! gee endif endfunction " " MoveToWordBegin() " Move to the word begin. " function! s:MoveToWordBegin() if line(".") =3D=3D 1 normal! wb else normal! gew endif endfunction " " MoveToFirstWordEnd() " Move to the first word end after the comment leader. " function! s:MoveToFirstWordEnd(leader_width) let i =3D a:leader_width + 1 execute "normal! " . i . "|" call s:MoveToWordEnd() endfunction " " TabooRuleMatch(taboo_rule_list, char) " Return true when the character matches one of taboo_rule_list " function! s:TabooRuleMatch(taboo_rule_list, char) " add spaces to char so to match exactly one of the list if strlen(a:char) > 1 let ch =3D a:char . " " else let ch =3D a:char . " " endif " escape the special character return a:taboo_rule_list =3D~ escape(ch, '^.*\$~[]') endfunction call DoMappings() " vi:set ts=3D8 sts=3D2 sw=3D2 tw=3D0: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D /* * Don't frown. * Don't complain. * Don't touch yourself. */ |
From: Simon L. <wzh...@sp...> - 2003-08-26 09:04:45
|
Dasn, Can you write up a short description of this plugin? What is it good at exactly? I nearly had to go through the code to figure out. On Mon, 25 Aug 2003 14:26:26 +0800, "Dasn Cups" <Da...@my...> said: > I happened to find this plugin file which can help us format multibyte > text. I hope it can be useful. -- Simon Liang wzh...@sp... -- http://www.fastmail.fm - IMAP accessible web-mail |