我的GVim配置
工作中,我大部分时间都是和VIM打交道的,甚至Windows下的编程也开始完全用GVIM替代Editplus。这两天对自己的vimrc文件做了一下整理。同时给每一行的配置增加了注释。整理完成之后,好用多了,因为借鉴了很多网友的经验,所以本着分享的精神公布出来,希望有朋友能用上。
另外,我这份_vimrc配置使用的字体是:YaHei Mono,如果您没有此字体,可以到这里下载:(下载YaHei Mono字体)。下载后放到Windows文件夹下的fonts目录里即可。如果你不想用YaHei Mono字体,那么有一个替代方案就是用Courier_New字体,需要修改以下配置:
- " 设置显示字体
- if has("win32")
- " set guifont=Courier_New:h11:cANSI
- set guifont=YaHei\ Mono:h11
- "set guifontwide=Microsoft\ Yahei\ Monotype:h11
- "set guifont=YaHei\ Consolas\ Hybrid:h12
- endif
将“set guifont=YaHei\ Mono:h11”注掉,同时把“set guifont=Courier_New:h11:cANSI”项打开即可。
以下是配置文件全部内容:
- " ***************Vimrc files for GVim *************
- " * CreateDate : Apr 20,2010
- " * LastModified : Apr 20,2010
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- " 全局设定 "
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- " 不要使用vi的键盘模式,而是vim自己的
- set nocompatible
- " 加载配置。
- behave mswin
- "设置快速编辑.vimrc文件 ,e 编辑.vimrc
- map <silent> <leader>e :call SwitchToBuf("~/_vimrc")<cr>
- "保存.vimrc文件后会自动调用新的.vimrc
- autocmd! bufwritepost .vimrc source ~/_vimrc
- " 设定解码
- if has("multi_byte")
- " When 'fileencodings' starts with 'ucs-bom', don't do this manually
- "set bomb
- set fileencodings=ucs-bom,utf-8,chinese,taiwan,japan,korea,latin1
- " CJK environment detection and corresponding setting
- if v:lang =~ "^zh_CN"
- " Simplified Chinese, on Unix euc-cn, on MS-Windows cp936
- set encoding=utf-8
- set termencoding=utf-8
- if &fileencoding == ''
- set fileencoding=utf-8
- endif
- elseif v:lang =~ "^zh_TW"
- " Traditional Chinese, on Unix euc-tw, on MS-Windows cp950
- set encoding=euc-tw
- set termencoding=euc-tw
- if &fileencoding == ''
- set fileencoding=euc-tw
- endif
- elseif v:lang =~ "^ja_JP"
- " Japanese, on Unix euc-jp, on MS-Windows cp932
- set encoding=euc-jp
- set termencoding=euc-jp
- if &fileencoding == ''
- set fileencoding=euc-jp
- endif
- elseif v:lang =~ "^ko"
- " Korean on Unix euc-kr, on MS-Windows cp949
- set encoding=euc-kr
- set termencoding=euc-kr
- if &fileencoding == ''
- set fileencoding=ecu-kr
- endif
- endif
- " Detect UTF-8 locale, and override CJK setting if needed
- if v:lang =~ "utf8$" || v:lang =~ "UTF-8$"
- set encoding=utf-8
- endif
- else
- echoerr 'Sorry, this version of (g)Vim was not compiled with "multi_byte"'
- endif
- " browsedir设置
- set browsedir=buffer
- " 自动格式化设置
- filetype indent on
- set autoindent
- set smartindent
- " 设置备份及备份目录。
- set backspace=indent,eol,start
- set backupdir=D:\vim_back_files
- set autochdir
- " history文件中需要记录的行数,恢复必须用到。
- set history=1024
- " 窗口最大化
- autocmd GUIEnter * simalt ~x
- " 解决菜单乱码,先指定语言。
- set langmenu=zh_CN.UTF-8
- source $VIMRUNTIME/vimrc_example.vim
- source $VIMRUNTIME/mswin.vim
- language message zh_CN.UTF-8
- set fileencodings=utf-8,GB2312,cp936,gb18030,big5,euc-jp,euc-kr,latin1
- " 在处理未保存或只读文件的时候,弹出确认
- set confirm
- " 共享外部剪贴板
- set clipboard+=unnamed
- " 显示未完成命令
- set showcmd
- " 侦测文件类型
- filetype on
- " 载入文件类型插件
- filetype plugin on
- " 为特定文件类型载入相关缩进文件
- filetype indent on
- " 保存全局变量
- set viminfo+=!
- " 带有如下符号的单词不要被换行分割
- set iskeyword+=_,$,@,%,#,-
- " 语法高亮
- syntax on
- " 设置不兼容模式
- set nocp
- " 设置鼠标支持
- set mouse=a
- " 不要生成swap文件
- setlocal noswapfile
- " 当buffer被丢弃时隐藏
- set bufhidden=hide
- " 保存窗口大小
- set sessionoptions+=resize
- " C++头文件识别
- au BufEnter /usr/include/c++/* setf cpp
- au BufEnter /usr/include/g++-3/* setf cpp
- " GNU标准
- au BufEnter /usr/* call GnuIndent()
- " 显示行号
- set number
- " tab宽度
- set tabstop=4
- set cindent shiftwidth=4
- set autoindent shiftwidth=4
- " C/C++注释
- set comments=://
- " 修正自动C式样注释功能 <2005/07/16>
- set comments=s1:/*,mb:*,ex0:/
- " 增强检索功能
- set tags=./tags,./../tags,./**/tags
- " 保存文件格式
- set fileformats=unix,dos
- " 文件被其他程序修改时自动载入
- set autoread
- " 高亮字符,让其不受100列限制
- :highlight OverLength ctermbg=red ctermfg=white guibg=red guifg=white
- :match OverLength '\%101v.*'
- " 总是显示状态行
- set laststatus=2
- " 状态行颜色
- " highlight StatusLine guifg=SlateBlue guibg=Yellow
- highlight StatusLine guifg=SlateBlue guibg=White
- highlight StatusLineNC guifg=Gray guibg=White
- " 我的状态行显示的内容(包括文件类型和解码)
- set statusline=[%n]%<%f%y%h%m%r%=[%b\ 0x%B]\ %l\ of\ %L,%c%V\ Page\ %N\ %P
- " 设置命令行高度为2行
- set cmdheight=1
- " 命令行补全
- set wildmenu
- " 自动补全括号,包括大括号
- :inoremap ( ()<ESC>i
- :inoremap ) <c-r>=ClosePair(')')<CR>
- :inoremap { {}<ESC>i
- :inoremap } <c-r>=ClosePair('}')<CR>
- :inoremap [ []<ESC>i
- :inoremap ] <c-r>=ClosePair(']')<CR>
- :inoremap < <><ESC>i
- :inoremap > <c-r>=ClosePair('>')<CR>
- " 打开文件时,总是跳到退出之前的光标处
- autocmd BufReadPost *
- \ if line("'\"") > 0 && line("'\"") <= line("$") |
- \ exe "normal! g`\"" |
- \ endif
- " 用浅色高亮当前行
- if has("gui_running")
- autocmd InsertLeave * se nocul
- autocmd InsertEnter * se cul
- endif
- filetype plugin on "允许使用ftplugin目录下的文件类型特定脚本
- filetype indent on "允许使用indent目录下的文件类型缩进
- " 设置自动粘贴功能。
- set pastetoggle=<F3>
- " 设置以缩进的方式自动折叠和设置快捷方式
- set foldmethod=indent
- " map <F3> zO " 打开折叠
- map <F4> zc " 关闭折叠
- map <F5> zR " 打开所有折叠
- map <F6> zM " 关闭所有折叠
- " 保存代码文件前自动修改最后修改时间
- au BufWritePre *.sh call TimeStamp('#')
- au BufWritePre .vimrc,*.vim call TimeStamp('"')
- au BufWritePre *.c,*.h call TimeStamp('//')
- au BufWritePre *.cpp,*.hpp call TimeStamp('//')
- au BufWritePre *.cxx,*.hxx call TimeStamp('//')
- au BufWritePre *.java call TimeStamp('//')
- au BufWritePre *.rb call TimeStamp('#')
- au BufWritePre *.py call TimeStamp('#')
- au BufWritePre Makefile call TimeStamp('#')
- au BufWritePre *.php
- \call TimeStamp('<?php //', '?>')
- au BufWritePre *.html,*htm
- \call TimeStamp('<!--', '-->')
- " 更改Leader为","
- let g:C_MapLeader = ','
- " 设置显示字体
- if has("win32")
- " set guifont=Courier_New:h11:cANSI
- set guifont=YaHei\ Mono:h11
- "set guifontwide=Microsoft\ Yahei\ Monotype:h11
- "set guifont=YaHei\ Consolas\ Hybrid:h12
- endif
- ab xmain int main(int argc, char *argv[])<cr>{<cr>}<up><cr>return
- " 使用 murphy 调色板
- colo murphy
- " 不要闪烁
- set novisualbell
- " 能够漂亮地显示.NFO文件
- set encoding=utf-8
- function! SetFileEncodings(encodings)
- let b:myfileencodingsbak=&fileencodings
- let &fileencodings=a:encodings
- endfunction
- function! RestoreFileEncodings()
- let &fileencodings=b:myfileencodingsbak
- unlet b:myfileencodingsbak
- endfunction
- au BufReadPre *.nfo call SetFileEncodings('cp437')|set ambiwidth=single
- au BufReadPost *.nfo call RestoreFileEncodings()
- " 用空格键来开关折叠
- set foldenable
- set foldmethod=manual
- nnoremap <space> @=((foldclosed(line('.')) < 0) ? 'zc' : 'zo')<CR>
- " 隐藏掉菜单和工具条。
- set guioptions-=m
- set guioptions-=T
- map <silent> <F2> :if &guioptions =~# 'T' <Bar>
- \set guioptions-=T <Bar>
- \set guioptions-=m <bar>
- \else <Bar>
- \set guioptions+=T <Bar>
- \set guioptions+=m <Bar>
- \endif<CR>
- " 标签页设置
- if has("gui_running")
- set showtabline=2
- map! tn tabnew
- nmap <C-c> :tabclose<CR>
- endif
- " 标签页只显示文件名
- function ShortTabLabel ()
- let bufnrlist = tabpagebuflist (v:lnum)
- let label = bufname (bufnrlist[tabpagewinnr (v:lnum) -1])
- let filename = fnamemodify (label, ':t')
- return filename
- endfunction
- set guitablabel=%{ShortTabLabel()}
- " 使回格键(backspace)正常处理indent, eol, start等
- set backspace=eol,start,indent
- " 允许backspace和光标键跨越行边界
- " set whichwrap+=<,>,h,l
- " 可以在buffer的任何地方使用鼠标(类似office中在工作区双击鼠标定位)
- set mouse=a
- set selection=exclusive
- set selectmode=mouse,key
- " 启动的时候不显示那个援助索马里儿童的提示
- set shortmess=atI
- " 通过使用: commands命令,告诉我们文件的哪一行被改变过
- set report=0
- " 不让vim发出讨厌的滴滴声
- set noerrorbells
- " 在被分割的窗口间显示空白,便于阅读
- set fillchars=vert:\ ,stl:\ ,stlnc:\
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- " 搜索和匹配 "
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- " 高亮显示匹配的括号
- set showmatch
- " 匹配括号高亮的时间(单位是十分之一秒)
- set matchtime=3
- " 在搜索的时候忽略大小写
- set ignorecase
- " 不要高亮被搜索的句子(phrases)
- " set nohlsearch
- " 在搜索时,输入的词句的逐字符高亮(类似firefox的搜索)
- set incsearch
- " 输入:set list命令是应该显示些啥?
- set listchars=tab:\|\ ,trail:.,extends:>,precedes:<,eol:$
- " Tab补全时忽略这些忽略这些
- set wildignore=*.o,*.obj,*.bak,*.exe
- " 光标移动到buffer的顶部和底部时保持3行距离
- set scrolloff=3
- "搜索出之后高亮关键词
- set hlsearch
- nmap <silent> <leader><cr> :noh<cr>
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- " CTags的设定 "
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- set tags=tags;
- " 按照名称排序
- let Tlist_Sort_Type = "name"
- " 在右侧显示窗口
- let Tlist_Use_Right_Window = 1
- " 压缩方式
- let Tlist_Compart_Format = 1
- " 如果只有一个buffer,kill窗口也kill掉buffer
- let Tlist_Exist_OnlyWindow = 1
- " 不要关闭其他文件的tags
- let Tlist_File_Fold_Auto_Close = 0
- " 不要显示折叠树
- let Tlist_Enable_Fold_Column = 0
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- " 快捷键映射 "
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- "设置其他快捷键
- map <F7> :vsplit<ENTER>:edit `pwd`<ENTER>i
- "F7 打开左侧垂直窗口选择待编辑的文件
- " 自动完成的缩进。
- if has("autocmd")
- if has("gui")
- autocmd WinLeave * set nocursorline nocursorcolumn
- autocmd WinEnter * set cursorline cursorcolumn
- else
- autocmd WinLeave * set nocursorline nocursorcolumn
- autocmd WinEnter * set cursorline nocursorcolumn
- endif
- " Enable file type detection.
- " load view saved by the mkview command
- autocmd FileType * loadview
- autocmd FileType * set noexpandtab
- autocmd BufWinEnter * loadview
- " Use the default filetype settings, so that mail gets 'tw' set to 72,
- " 'cindent' is on in C files, etc.
- " Also load indent files, to automatically do language-dependent indenting.
- filetype plugin indent on
- " In text files, always limit the width of text to 78 characters
- autocmd FileType text set textwidth=78 expandtab softtabstop=4
- autocmd FileType sh set shiftwidth=4 expandtab softtabstop=4
- autocmd FileType php set shiftwidth=4 expandtab softtabstop=4
- autocmd FileType html set shiftwidth=4 expandtab softtabstop=4
- autocmd FileType javascript set shiftwidth=4 expandtab softtabstop=4
- autocmd FileType python set shiftwidth=4 expandtab softtabstop=4
- autocmd FileType ruby set shiftwidth=4 expandtab softtabstop=4
- autocmd FileType eruby set shiftwidth=4 expandtab softtabstop=4
- autocmd FileType sql set shiftwidth=4 expandtab softtabstop=4
- " When editing a file, always jump to the last known cursor position.
- " Don't do it when the position is invalid or when inside an event handler
- " (happens when dropping a file on gvim).
- autocmd BufReadPost *
- \ if line("'\"") > 0 && line("'\"") <= line("$") |
- \ execute "normal g`\"" |
- \ endif
- augroup prog
- " Remove all cprog autocommands
- autocmd!
- " When starting to edit a file:
- " For C and C++ files set formatting of comments and set C-indenting on.
- " For other files switch it off.
- " Don't change the order, it's important that the line with * comes first.
- autocmd FileType * set formatoptions=tcoql nocindent comments&
- autocmd BufWinLeave *.sh,*.c,*.cpp,*.perl,*.py mkview
- autocmd BufWinEnter *.sh,*.c,*.cpp,*.perl,*.py silent loadview
- function! CleverTab()
- if strpart( getline('.'), 0, col('.')-1 ) =~ '^\s*$'
- return "\<Tab>"
- else
- return "\<C-N>"
- endfunction
- autocmd FileType c,cpp noremap! <S-Tab> <C-R>=CleverTab()<CR>
- autocmd FileType c,cpp noremap! <C-]> <C-X><C-]>
- autocmd FileType c,cpp noremap! <C-F> <C-X><C-F>
- autocmd FileType c,cpp noremap! <C-D> <C-X><C-D>
- autocmd FileType c,cpp noremap! <C-L> <C-X><C-L>
- autocmd FileType c,cpp,sh,perl,python set fileformat=unix
- autocmd FileType sh set formatoptions=croql cindent comments=b:#
- autocmd FileType c,cpp set expandtab shiftwidth=4 softtabstop=4
- augroup END
- endif " has("autocmd")
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- " PYTHON 相关的设置 "
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- "Python 文件的一般设置,比如不要 tab 等
- "设置自动缩进为4,插入模式里: 插入 <Tab> 时使用合适数量的空格。
- "要插入实际的制表,可用 CTRL-V<Tab>
- autocmd FileType python setlocal expandtab | setlocal shiftwidth=4 |
- \setlocal softtabstop=4 | setlocal textwidth=76 |
- \tabstop=4
- "pydiction插件设置(需要安装pydiction插件)
- "设置python的字典路径
- let g:pydiction_location = '~/.vim/skeleton/pydict/complete-dict'
- "设置pydict的菜单高度
- let g:pydiction_menu_height = 10
- "Python Unittest 的一些设置
- "在编写 Python 代码及 unittest 测试时不需要离开 vim
- "键入 :make 或者点击 gvim 工具条上的 make 按钮就自动执行测试用例
- autocmd FileType python compiler pyunit
- autocmd FileType python setlocal makeprg=python\ ~/.vim/skeleton/alltests.py
- autocmd BufNewFile,BufRead test*.py setlocal makeprg=python\ %
- "自动使用新文件模板(需要提前准备skeleton相关文件)
- autocmd BufNewFile test*.py 0r ~/.vim/skeleton/test.py
- autocmd BufNewFile alltests.py 0r ~/.vim/skeleton/alltests.py
- autocmd BufNewFile wx*.py 0r ~/.vim/skeleton/wxskeleton.py
- autocmd BufNewFile *.py 0r ~/.vim/skeleton/skeleton.py
- "设置= + - * 前后自动空格
- "设置,后面自动添加空格
- au FileType python inoremap <buffer>= <c-r>=EqualSign('=')<CR>
- au FileType python inoremap <buffer>+ <c-r>=EqualSign('+')<CR>
- au FileType python inoremap <buffer>- <c-r>=EqualSign('-')<CR>
- au FileType python inoremap <buffer>* <c-r>=EqualSign('*')<CR>
- au FileType python inoremap <buffer>/ <c-r>=EqualSign('/')<CR>
- au FileType python inoremap <buffer>> <c-r>=EqualSign('>')<CR>
- au FileType python inoremap <buffer>< <c-r>=EqualSign('<')<CR>
- au FileType python inoremap <buffer>: <c-r>=Swap()<CR>
- au FileType python inoremap <buffer>, ,<space>
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- " 脚本内部用到的自定义函数 "
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- "
- "函数后面加上!是防止vimrc文件重新载入时报错
- "实现光标位置自动交换:) --> ):
- function! Swap()
- if getline('.')[col('.') - 1] =~ ")"
- return "\<ESC>la:"
- else
- return ":"
- endif
- endf
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- "
- "实现+-*/前后自动添加空格,逗号后面自动添加空格,适用python
- "支持+= -+ *= /+格式
- function! EqualSign(char)
- if a:char =~ '=' && getline('.') =~ ".*("
- return a:char
- endif
- let ex1 = getline('.')[col('.') - 3]
- let ex2 = getline('.')[col('.') - 2]
- if ex1 =~ "[-=+><>\/\*]"
- if ex2 !~ "\s"
- return "\<ESC>i".a:char."\<SPACE>"
- else
- return "\<ESC>xa".a:char."\<SPACE>"
- endif
- else
- if ex2 !~ "\s"
- return "\<SPACE>".a:char."\<SPACE>\<ESC>a"
- else
- return a:char."\<SPACE>\<ESC>a"
- endif
- endif
- endf
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- "
- "实现括号的自动配对后防止重复输入),适用python
- function! ClosePair(char)
- if getline('.')[col('.') - 1] == a:char
- return "\<Right>"
- else
- return a:char
- endif
- endf
- """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- "
- "SwitchToBuf()实现它在所有标签页的窗口中查找指定的文件名,如果找到这样一个窗口,
- "就跳到此窗口中;否则,它新建一个标签页来打开vimrc文件
- "上面自动编辑.vimrc文件用到的函数
- function! SwitchToBuf(filename)
- let bufwinnr = bufwinnr(a:filename)
- if bufwinnr != -1
- exec bufwinnr . "wincmd w"
- return
- else
- " find in each tab
- tabfirst
- let tab = 1
- while tab <= tabpagenr("$")
- let bufwinnr = bufwinnr(a:filename)
- if bufwinnr != -1
- exec "normal " . tab . "gt"
- exec bufwinnr . "wincmd w"
- return
- endif
- tabnext
- let tab = tab + 1
- endwhile
- " not exist, new tab
- exec "tabnew " . a:filename
- endif
- endfunction
- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- "
- "Last change用到的函数,返回时间,能够自动调整位置
- function! TimeStamp(...)
- let sbegin = ''
- let send = ''
- if a:0 >= 1
- let sbegin = a:1.'\s*'
- endif
- if a:0 >= 2
- let send = ' '.a:2
- endif
- let pattern = 'Last Change: .\+'
- \. send
- let pattern = '^\s*' . sbegin . pattern . '\s*$'
- let now = strftime('%Y-%m-%d %H:%M:%S',
- \localtime())
- let row = search(pattern, 'n')
- if row == 0
- let now = a:1 . ' Last Change: '
- \. now . send
- call append(2, now)
- else
- let curstr = getline(row)
- let col = match( curstr , 'Last')
- let spacestr = repeat(' ',col - 1)
- let now = a:1 . spacestr . 'Last Change: '
- \. now . send
- call setline(row, now)
- endif
- endfunction
我们的开源Twitter客户端:TinyTui2
TinyTui是由印客网前技术总监老庄(表伟)发起的一个开源项目,后来由于共同的兴趣爱好,我和另外一个朋友felixding也加入到了这个团队当中。项目虽然不大,但却凝聚了我们不少心血,当然,做为后来者加入的我,贡献有限,主要还是前面两位牛人在开发。目前产品正在完善当中,不过已经基本上满足需求。
一、关于TinyTui2:
TinyTui2是一个基于Twitter API构建的Twitter客户端程序,目标是建立一个高可用性、高智能的代_理平台,为墙内的互联网用户搭建起通往Twitter的桥梁。为了防止信息过载,我们在这个平台上加入了贝叶斯算法(bayesian,wiki:点这里),试图应用这个算法的自我学习机制,来过滤掉一些无意义的噪音,让用户能更有效Touch到目标信息。
TinyTui2为开源程序,基于GPL协议,可二次开发,当然,我们也要求二次开发人员须具备能忍受我们在代码间叽叽歪歪的废话而不疯掉的心理承受能力,除此没其它的要求。祝您好运,感谢祖国,感谢父母,感谢国民党,感谢功夫网,感谢你丫挺的。
项目主页:http://code.google.com/p/tinytui2/
二、我们的信念:
以佛主如来的名义,Fuck G_F_W 一万年。阿门。
三、系统安装:
1、将程序上传到你的WEB目录下,请保证域名指向的根目录是:apps
2、保证:cache目录及其子目录可写。
3、保证:libs/b8-0.4.4/etc/config_storage.php文件可写。
4、运行:http://youdomain.com/install
5、输入你的数据库账号及密码。点击安装。
6、安装成功之后,请删除apps目录下的install文件夹。
四、目录结构:
/----apps - WEB应用程序所在目录
| |
| |----install -- 系统安装文件
| |
| |----src -- 静态资源文件
|
|--conf - 网站配置文件所在目录
|
|--libs - 库文件,包括开源的库,b8和smarty
|
|--view - 模板所在目录
|
|--lang - 语言包所在目录
|
|--cache - 缓存目录(此目录以及子目录必须设置为可写)
| |
| | ------ smarty_cache -- smarty缓存目录,可在配置文件里设置是否开启。
| |
| | ------ templates_c -- smarty模板编译默认目录。
|
|--Doc - 文档目录,包括原始的参考资源,以及原始的PSD文件等。
五、系统配置:
要运行本套系统,需要满足如下条件:
1、墙外的虚拟主机或VPS一台。
2、PHP+MySQL环境,虚拟主机要有可读写权限。
3、不怕被墙的域名一个[可选]。
六、开发人员Twitter及BLOG:
@zhuangbiaowei - http://www.zhuangbiaowei.cn
@felixding - http://dingyu.me/blog/
@handaoliang - http://www.handaoliang.com
七、其它:
这是PHP版本,后续的Python+Tornado+GAE版本正在开发当中。
线上版本:http://www.ijiyi.com,欢迎关注并使用。
基于JSON格式数据的Ajax分页实现
很早就想写一篇关于Ajax分页的文章,只是一直偷懒,拖到现在。有这个念头,是因为我看到现在大部分的WEB分页实现,都是在服务器端做,即便是有一些号称用Ajax实现的,也无非是从服务器端传一组HTML到前端来展示。从纯数据传输的角度来讲,这是相当不靠谱的事情,明明可以纯JSON传输的数据,为什么要附带上这么多冗余的HTML呢?因为既然是和页面相关的事情嘛,自然应该都交给前端去处理。
实现起来其实很简单,先实现分页逻辑:
- //创建全局对象。
- var handaoliang = {};
- //设定命名空间。
- handaoliang.func = {};
- (function(){
- /**
- * 这里传入的数据里必须包含三个Key键:
- * allRecords - 所有记录数。
- * allPageNum - 所有页面数。
- * currentPage - 当前页。
- **/
- handaoliang.func.AjaxPage = function(my_page_data){
- this.record_num = parseInt(my_page_data.allRecords);
- this.all_page_num = parseInt(my_page_data.allPageNum);
- this.cur_page = parseInt(my_page_data.currentPage);
- //在多页的时候,一次显示多少页。
- this.show_page_num = 8;
- /**
- * 画分页内容的时候,要求传入两个参数:
- * container - 显示分页内容的容器。
- * call_back_fun_name - 回调函数。
- **/
- this.draw_page = function(container,call_back_fun_name){
- var loop_num = this.all_page_num > this.show_page_num ? this.show_page_num : this.all_page_num;
- var page_info = "<p style='clear:both; height:20px; margin-bottom: 8px; font-weight: bold;'>一共有"
- + " " + this.record_num + " 条记录,"
- + "分成 " + this.all_page_num + " 页显示,"
- + "当前第 " + this.cur_page + " 页。</p>";
- //只有当全部分页大于1的时候,才显示“第一页”。
- if(this.all_page_num > 1){
- page_info += "<a href='javascript:" + call_back_fun_name + "(1);' class='page_link'>[第一页]</a> ";
- }
- //当当前页处于第一页的时候,即以第一页为参照页,往后画页面。
- if(this.all_page_num > 1 && this.cur_page == 1){
- for(var i = 1;i <= loop_num;i++){
- if(this.cur_page == i){
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + i + ");' class='page_link_num' style='font-weight:bold;'>" + i + "</a> ";
- }else{
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + i + ");' class='page_link_num'>" + i + "</a> ";
- }
- }
- page_info += "<a href='javascript:" + call_back_fun_name + "(2);' class='page_link'>[下一页]</a> ";
- }
- //当当前页处于第一页到最后一页的距离中间的时候,此时以当前页为参照,输出前多少页后多少页。
- if(this.cur_page > 1 && this.cur_page < this.all_page_num){
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + (parseInt(this.cur_page)-1) + ");' class='page_link'>[上一页]</a> ";
- //要先判断是否大于展示的页数。以避免出现负数的页码。
- if(this.cur_page > (parseInt(this.show_page_num)-1)/2){
- for(var i = (parseInt(this.show_page_num)-1)/2; i >= 1 ;i--){
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + (parseInt(this.cur_page)-i) + ");' class='page_link_num'>"
- + (parseInt(this.cur_page)-i) + "</a> ";
- }
- }else{//当当前页小于展示的页数时,不能多减,否则会出现负数页。
- for(var i = this.cur_page-1; i >= 1 ;i--){
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + (parseInt(this.cur_page)-i) + ");' class='page_link_num'>"
- + (parseInt(this.cur_page)-i) + "</a> ";
- }
- }
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + this.cur_page + ");' class='page_link_num' style='font-weight:bold;'>"
- + this.cur_page + "</a> ";
- if((parseInt(this.all_page_num)-parseInt(this.cur_page)) > (parseInt(this.show_page_num)-1)/2){
- //此时如果当前页小于展示页的一半,则需要多显示几页。以达到平衡。
- if(this.cur_page < (parseInt(this.show_page_num)-1)/2){
- var added_page = ((parseInt(this.show_page_num)-1)/2)-parseInt(this.cur_page)+1;
- for(var i = 1;i <= ((parseInt(this.show_page_num)-1)/2+added_page);i++){
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + (parseInt(this.cur_page)+i) + ");' class='page_link_num'>"
- + (parseInt(this.cur_page)+i) + "</a> ";
- }
- }else{
- for(var i = 1;i <= (parseInt(this.show_page_num)-1)/2;i++){
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + (parseInt(this.cur_page)+i) + ");' class='page_link_num'>"
- + (parseInt(this.cur_page)+i) + "</a> ";
- }
- }
- }else{
- for(var i = 1;i <= parseInt(this.all_page_num)-parseInt(this.cur_page); i++){
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + (parseInt(this.cur_page)+i) + ");' class='page_link_num'>"
- + (parseInt(this.cur_page)+i) + "</a> ";
- }
- }
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + (parseInt(this.cur_page)+1) + ");' class='page_link'>[下一页]</a> ";
- }
- //当当前页处于最后一页,并且包含的页面大于1页时,则由后往前画分页。
- if(this.all_page_num > 1 && this.cur_page == this.all_page_num){
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + (parseInt(this.cur_page)-1) + ");' class='page_link'>[上一页]</a> ";
- if(this.all_page_num > this.show_page_num){
- for(var i = this.show_page_num; i >= 1;i--){
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + (parseInt(this.cur_page)-i) + ");' class='page_link_num'>"
- + (parseInt(this.cur_page)-i) + "</a> ";
- }
- }else{
- for(var i = (this.all_page_num-1); i >= 1;i--){
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + (parseInt(this.cur_page)-i) + ");' class='page_link_num'>"
- + (parseInt(this.cur_page)-i) + "</a> ";
- }
- }
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + parseInt(this.cur_page) + ");' class='page_link_num' style='font-weight:bold;'>"
- + this.cur_page + "</a> ";
- }
- //只有当全部分页大于1的时候,才显示“最尾页”。
- if(this.all_page_num > 1){
- page_info += "<a href='javascript:" + call_back_fun_name + "(" + this.all_page_num + ");' class='page_link'>[最尾页]</a>";
- }
- container.innerHTML = page_info;
- };
- }
- })();
假设后端输出的分页信息为:
- {
- "page_info": {
- "record_num": 70,
- "current_page": "1",
- "page_num": 3
- }
- }
此时调用分页方法即可以获得分页效果(假设分页容器是:page_box):
- var doSetPageInfo = function(json_data){
- document.getElementById("page_box").innerHTML = '';
- if(typeof json_data.page_info != "undefined"
- && json_data.page_info != null
- && json_data.page_info.page_num != 0
- ){
- var AjaxPageObj = new handaoliang.func.AjaxPage({
- allRecords:json_data.page_info.record_num,
- allPageNum:json_data.page_info.page_num,
- currentPage:json_data.page_info.current_page
- });
- AjaxPageObj.draw_page(document.getElementById("page_box"),call_back_function);
- }
- }
至于后台,则只需根据传入的参数来实现分段取数据就可以了。当用户点击一个页面的时候,传数的页数乃是通过变量page来传递,这样就最大限度上的做到了运算和展示分离,同时也做到了客户端和服务器端数据传输量的最小化。
为Repoze.who开发的SSO插件
在架设ClueMapper的过程当中,由于ClueMapper是基于repoze.who做为登录认证模块的,所以为了适应需求,对repoze.who做了不少的改造,比如之前说过的给repoze.who加上LDAP认证即是改进之一。当然,在后来使用的过当中,并没有完全依赖于LDAP的谁机制,而是使用了SSO认证机制,这是目前很多公司内部普遍使用的认证机制之一。
其实这是第一次尝试写Repoze.who的中间件,在写之前仔细看了一遍repoze.who的代码,发现了不少有意思的东西,比如中间件的机制,等回头有时间,可以专门写一篇repoze.who解读。当然这是题外话,现在要说的,是这个SSO插件。
代码很简单,由于现在我们使用的SSO认证仅仅基于HTTP协议,所以只用urllib2就够了。下面是代码:
- # -*- coding: utf-8 -*-
- """
- SSO Plugins for Repoze.who
- Author: handaoliang <handaoliang@gmail.com>
- Basic usage:
- >>> from repoze.who.plugins import sso
- >>> sso_auth = sso.SSOAuthenticatorPlugin(SSO_URI,SSO_ORG_ID,SSO_SUB_ID,REMOTE_ADDR)
- >>> authenticators = [('sso_auth', sso_auth)]
- >>> pam = middleware.PluggableAuthenticationMiddleware(
- authfilter,
- identifiers,
- authenticators,
- challengers,
- mdproviders,
- classifier,
- challenge_decider,
- )
- """
- from zope.interface import implements
- import hashlib
- import urllib2
- from repoze.who.interfaces import IAuthenticator, IMetadataProvider
- class SSOAuthenticatorPlugin(object):
- implements(IAuthenticator)
- def __init__(self, ssoURI, orgID, subID,ipADDR):
- if ssoURI is None:
- raise ValueError('The SSO URL must be specified')
- self.sso_uri = ssoURI
- self.org_id = orgID
- self.sub_id = subID
- self.ip_address = ipADDR
- def authenticate(self, environ, identity):
- try:
- user_name = identity['login']
- password = identity['password']
- except (KeyError, TypeError, ValueError):
- return None
- auth_password = hashlib.md5(password).hexdigest().upper()
- auth_url = "%s?orgname=%s&sub=%s&user=%s&pwd=%s&ip=%s" \
- % (self.sso_uri,self.org_id,self.sub_id,user_name,auth_password,self.ip_address)
- #connecting....
- try:
- request_handle = urllib2.Request(auth_url)
- contents_handle = urllib2.urlopen(request_handle)
- return_data = contents_handle.read()
- _status = return_data.split("|")
- if int(_status[0]) == 1:
- return user_name
- else:
- return None
- except Exception,e:
- #catched this error:
- return None
- def __repr__(self):
- return '<%s %s>' % (self.__class__.__name__, id(self))
使用方法:
- from repoze.who.plugins import sso
- SSO_URI = "http://192.168.0.1:8000/SsoCertify";
- SSO_ORG_ID = 2
- SSO_SUB_ID = 992
- REMOTE_ADDR = '127.0.0.1'
- sso_auth = sso.SSOAuthenticatorPlugin(SSO_URI,SSO_ORG_ID,SSO_SUB_ID,REMOTE_ADDR)
- authenticators = [('sso_auth', sso_auth)]
- pam = middleware.PluggableAuthenticationMiddleware(
- authfilter,
- identifiers,
- authenticators,
- challengers,
- mdproviders,
- classifier,
- challenge_decider,
- )
本人较懒,没有做安装包,需要安装包的可以联系我。如果有多人需要,将考虑将它更完善。
取得某个文件夹下所有同类型文件
PHP有一个模块叫做mime_magic,用来判断文件的类型非常有效。使用它的mime_content_type函数,结合递归可以很方便的把某一个文件夹下的所同类型文件找出来,比如我因为某种需求要取出某个文件夹下所有的纯文本文件,即是写了一小段代码来递归(代码片段见下文)。
当然,这里并不是展示什么技巧性的东西,只是介绍性的说明一下有这样一个模块。记得很多年前初学写程序时,是根据文件的后缀来判断文件类型的,显然这是一件多么不靠谱的事情,如果现在还有人这么干,我想是要被耻笑的吧?脚本语言讨人喜爱之处就是它总是为我们提供很多很实用的库,这大大降低了我们的开发成本以及提高了开发效率,虽然,也因此增加了选择成本。比如我们刚刚所说的判断文件类型,即有人建议用PECL的FileInfo库来做。
需要连带说明一下,在Python中对MIME类型的处理,也有内置的一个模块叫mimetypes,可以很方便的取得一个文件的类型。
- >>> import mimetypes
- >>> mimetypes.guess_type('/home/handaoliang/bodybg.jpg')
- ('image/jpeg', None)
PHP取得某文件夹下所有的纯文本文件:
- #!/var/iapps/php/bin/php
- <?php
- class listFiles{
- public $fileLists;
- public function __construct(){
- $this->fileLists = array();
- }
- public function excuteList($baseDirName)
- {
- $myDirObj = dir($baseDirName);
- while($fileName = $myDirObj->read()){
- //如果获取到的文件属性是目录,并且不是.或者..,则再遍历一次。
- if((is_dir($baseDirName."/".$fileName)) && ($fileName != ".") && ($fileName != "..")){
- listFiles::excuteList("$baseDirName/$fileName");
- }else if(($fileName != ".") && ($fileName != "..")){
- //判断类型,将文本文件放到数组里。
- if("text/plain" == mime_content_type($baseDirName."/".$fileName)){
- array_push($this->fileLists,$baseDirName."/".$fileName);
- }
- //echo mime_content_type($baseDirName."/".$fileName)."\n";
- //$this->getFileType($baseDirName."/".$fileName);
- //echo "\n";
- //echo $baseDirName."/".$fileName."\n";
- }
- }
- $myDirObj->close();
- }
- }
- $fileListObj = new listFiles();
- $fileListObj->excuteList("/home/handaoliang/meeuu.com");
- $fileLists = $fileListObj->fileLists;
- print_r($fileLists);
- ?>