原文出处:http://blog.jobbole.com/58978/

第一次听说这个插件还是在偶然的情况下看到别人的博客,听说了这个插件的大名。本来打算在实训期间来完成安装的,无奈网实在不给力,也就拖到了回家的时候。在开始准备工作的时候就了解到这个插件不是很容易安装,安装的时候果然名不虚传。(关于这方面的内容,请查看另一篇文章)不过,有付出总有回报,安装之后用上这个插件,真心为这个插件的强大所折服。

那这个插件有何不同?

YouCompleteMe的特别之处

基于语义补全

总所周知,Vim是一款文本编辑器。也就是说,其最基础的工作就是编辑文本,而不管该文本的内容是什么。在Vim被程序员所使用后,其慢慢的被肩负了与IDE一样的工作,文本自动补全(ie.acp,omnicppcompleter),代码检查(Syntastic)等等工作。

针对文本自动补全这个功能来说,主要有两种实现方式。

基于文本

我们常用的omnicppcompleter,acp,vim自带的c-x, c-n的实现方式就是基于文本。更通俗的说法,其实就是一个字:

其通过文本进行一些正则表达式的匹配,再根据生成的tags(利用ctags生成)来实现自动补全的效果。

基于语义

顾名思义,其是通过分析源文件,经过语法分析以后进行补全。由于对源文件进行分析,基于语义的补全可以做到很精确。但是这显然是vim所不可能支持的。而且经过这么多年发展,由于语法分析有很高的难度,也一直没有合适的工具出现。直到,由apple支持的clang/llvm横空出世。YouCompleteMe也正是在clang/llvm的基础上进行构建的。

整合实现了多种插件

clang_complete

AutoComplPop

Supertab

neocomplcache

Syntastic(类似功能,仅仅针对c/c++/obj-c代码)

支持语言

c

c++

obj-c

c#

python

对于其他的语言,会调用vim设置的omnifunc来匹配,因此同样支持php,ruby等语言。

已知的有 * javascript —-tern_for_vim * ruby/java —-eclim

使用效果图

使用感受

和IDE一样,自动补全,

根据include的文件进行补全

不用再蹩脚的生成tags

补全非常精准,而且速度很快,不会有延迟(以前在大项目上,acp用起来实在是很卡)

支持类似tags的跳转,跳到定义处以及使用处

出错提示很智能,并且用起来真的是如丝般柔滑,不用输入:w进行强制检测

安装

说完了那么多好处,就要说到安装了。不同于以往其他vim插件,YCM是一款编译型的插件。在下载完后,需要手动编译后才能使用。对应其他的插件来说,仅仅就是把.vim的文件丢到相应文件夹下就可以。而这也加大了使用YCM的难度。

安装准备

最新版的Vim(7.3.584+),编译时添加+python标志(已经安装的可以通过vim --version查看)

cmake(mac可以通过homebrew安装,brew install cmake,ubuntu可以通过sudo apt-get install cmake)

安装vundle插件,用于安装管理vim的插件

mac下快速安装

在.vimrc中添加下列代码

Shell

Bundle 'Valloric/YouCompleteMe'

1

Bundle'Valloric/YouCompleteMe'

保存退出后打开vim,在正常模式下输入

Shell

:BundleInstall

1

:BundleInstall

等待vundle将YouCompleteMe安装完成

而后进行编译安装:

Shell

cd ~/.vim/bundle/YouCompleteMe

./install --clang-completer

1

2

cd~/.vim/bundle/YouCompleteMe

./install--clang-completer

如果不需要c-family的补全,可以去掉--clang-completer。如果需要c#的补全,请加上--omnisharp-completer。

正常来说,YCM会去下载clang的包,如果已经有,也可以用系统--system-libclang。

就这样,安装结束。打开vim,如果没有提示YCM未编译,则说明安装已经成功了。

手动编译安装

安装的脚本并不是什么时候都好用,至少对我来说是这样的。安装完之后出现了问题,参考issue#809。

在用:BundleInstall安装完成或者使用

Shell

git clone --recursive https://github.com/Valloric/YouCompleteMe.git

1

git clone--recursive https://github.com/Valloric/YouCompleteMe.git

获取最新的仓库,而后使用git submodule update --init --recursive确认仓库的完整性后,开始安装流程。

下载最新的clang二进制文件 YCM要求clang版本 > 3.2,一般来说都是下载最新的。

安装python-dev.(ubuntu下使用sudo apt-get install python-dev,mac下默认提供,否则请安装command line tools)

编译

Shell

cd ~

mkdir ycm_build

cd ycm_build

cmake -G “Unix Makefiles” -DPATH_TO_LLVM_ROOT=~/ycm_temp/llvm_root_dir . ~/.vim/bundle/YouCompleteMe/cpp make ycm_support_libs

1

2

3

4

cd~

mkdirycm_build

cdycm_build

cmake-G“Unix Makefiles”-DPATH_TO_LLVM_ROOT=~/ycm_temp/llvm_root_dir.~/.vim/bundle/YouCompleteMe/cpp makeycm_support_libs

这里需要注意的是,~/ycm_temp/llvm_root_dir中包含的是根据第一步下载的压缩包解压出来的内容(包括include, bin等等文件)。

这样就完成了,开始感受YCM提供的完全不逊色于大型IDE所提供的自动补全功能吧。

配置

不同于很多vim插件,YCM首先需要编译,另外还需要有配置。在vim启动后,YCM会找寻当前路径以及上层路径的.ycm_extra_conf.py.在~/.vim/bundle/YouCompleteMe/cpp/ycm/.ycm_extra_conf.py中提供了默认的模板。也可以参考我的(就在模板上改改而已)。不过这个解决了标准库提示找不到的问题。

一般来说,我会在~目录下放一个默认的模板,而后再根据不同的项目在当前目录下再拷贝个.ycm_extra_conf.py。

Shell

# This file is NOT licensed under the GPLv3, which is the license for the rest

# of YouCompleteMe.

#

# Here's the license text for this file:

#

# This is free and unencumbered software released into the public domain.

#

# Anyone is free to copy, modify, publish, use, compile, sell, or

# distribute this software, either in source code form or as a compiled

# binary, for any purpose, commercial or non-commercial, and by any

# means.

#

# In jurisdictions that recognize copyright laws, the author or authors

# of this software dedicate any and all copyright interest in the

# software to the public domain. We make this dedication for the benefit

# of the public at large and to the detriment of our heirs and

# successors. We intend this dedication to be an overt act of

# relinquishment in perpetuity of all present and future rights to this

# software under copyright law.

#

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR

# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,

# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR

# OTHER DEALINGS IN THE SOFTWARE.

#

# For more information, please refer to

import os

import ycm_core

# These are the compilation flags that will be used in case there's no

# compilation database set (by default, one is not set).

# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.

flags = [

'-Wall',

'-Wextra',

#'-Werror',

#'-Wc++98-compat',

'-Wno-long-long',

'-Wno-variadic-macros',

'-fexceptions',

'-stdlib=libc++',

# THIS IS IMPORTANT! Without a "-std=" flag, clang won't know which

# language to use when compiling headers. So it will guess. Badly. So C++

# headers will be compiled as C headers. You don't want that so ALWAYS specify

# a "-std=".

# For a C project, you would set this to something like 'c99' instead of

# 'c++11'.

'-std=c++11',

# ...and the same thing goes for the magic -x option which specifies the

# language that the files to be compiled are written in. This is mostly

# relevant for c++ headers.

# For a C project, you would set this to 'c' instead of 'c++'.

'-x',

'c++',

'-I',

'.',

'-isystem',

'/usr/include',

'-isystem',

'/usr/local/include',

'-isystem',

'/Library/Developer/CommandLineTools/usr/include',

'-isystem',

'/Library/Developer/CommandLineTools/usr/bin/../lib/c++/v1',

]

# Set this to the absolute path to the folder (NOT the file!) containing the

# compile_commands.json file to use that instead of 'flags'. See here for

# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html

#

# Most projects will NOT need to set this to anything; you can just change the

# 'flags' list of compilation flags. Notice that YCM itself uses that approach.

compilation_database_folder = ''

if os.path.exists( compilation_database_folder ):

database = ycm_core.CompilationDatabase( compilation_database_folder )

else:

database = None

SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]

def DirectoryOfThisScript():

return os.path.dirname( os.path.abspath( __file__ ) )

def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):

if not working_directory:

return list( flags )

new_flags = []

make_next_absolute = False

path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]

for flag in flags:

new_flag = flag

if make_next_absolute:

make_next_absolute = False

if not flag.startswith( '/' ):

new_flag = os.path.join( working_directory, flag )

for path_flag in path_flags:

if flag == path_flag:

make_next_absolute = True

break

if flag.startswith( path_flag ):

path = flag[ len( path_flag ): ]

new_flag = path_flag + os.path.join( working_directory, path )

break

if new_flag:

new_flags.append( new_flag )

return new_flags

def IsHeaderFile( filename ):

extension = os.path.splitext( filename )[ 1 ]

return extension in [ '.h', '.hxx', '.hpp', '.hh' ]

def GetCompilationInfoForFile( filename ):

# The compilation_commands.json file generated by CMake does not have entries

# for header files. So we do our best by asking the db for flags for a

# corresponding source file, if any. If one exists, the flags for that file

# should be good enough.

if IsHeaderFile( filename ):

basename = os.path.splitext( filename )[ 0 ]

for extension in SOURCE_EXTENSIONS:

replacement_file = basename + extension

if os.path.exists( replacement_file ):

compilation_info = database.GetCompilationInfoForFile(

replacement_file )

if compilation_info.compiler_flags_:

return compilation_info

return None

return database.GetCompilationInfoForFile( filename )

def FlagsForFile( filename, **kwargs ):

if database:

# Bear in mind that compilation_info.compiler_flags_ does NOT return a

# python list, but a "list-like" StringVec object

compilation_info = GetCompilationInfoForFile( filename )

if not compilation_info:

return None

final_flags = MakeRelativePathsInFlagsAbsolute(

compilation_info.compiler_flags_,

compilation_info.compiler_working_dir_ )

# NOTE: This is just for YouCompleteMe; it's highly likely that your project

# does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR

# ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT.

#try:

# final_flags.remove( '-stdlib=libc++' )

#except ValueError:

# pass

else:

relative_to = DirectoryOfThisScript()

final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )

return {

'flags': final_flags,

'do_cache': True

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

# This file is NOT licensed under the GPLv3, which is the license for the rest

# of YouCompleteMe.

#

# Here's the license text for this file:

#

# This is free and unencumbered software released into the public domain.

#

# Anyone is free to copy, modify, publish, use, compile, sell, or

# distribute this software, either in source code form or as a compiled

# binary, for any purpose, commercial or non-commercial, and by any

# means.

#

# In jurisdictions that recognize copyright laws, the author or authors

# of this software dedicate any and all copyright interest in the

# software to the public domain. We make this dedication for the benefit

# of the public at large and to the detriment of our heirs and

# successors. We intend this dedication to be an overt act of

# relinquishment in perpetuity of all present and future rights to this

# software under copyright law.

#

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR

# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,

# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR

# OTHER DEALINGS IN THE SOFTWARE.

#

# For more information, please refer to

import os

import ycm_core

# These are the compilation flags that will be used in case there's no

# compilation database set (by default, one is not set).

# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.

flags=[

'-Wall',

'-Wextra',

#'-Werror',

#'-Wc++98-compat',

'-Wno-long-long',

'-Wno-variadic-macros',

'-fexceptions',

'-stdlib=libc++',

# THIS IS IMPORTANT! Without a "-std=" flag, clang won't know which

# language to use when compiling headers. So it will guess. Badly. So C++

# headers will be compiled as C headers. You don't want that so ALWAYS specify

# a "-std=".

# For a C project, you would set this to something like 'c99' instead of

# 'c++11'.

'-std=c++11',

# ...and the same thing goes for the magic -x option which specifies the

# language that the files to be compiled are written in. This is mostly

# relevant for c++ headers.

# For a C project, you would set this to 'c' instead of 'c++'.

'-x',

'c++',

'-I',

'.',

'-isystem',

'/usr/include',

'-isystem',

'/usr/local/include',

'-isystem',

'/Library/Developer/CommandLineTools/usr/include',

'-isystem',

'/Library/Developer/CommandLineTools/usr/bin/../lib/c++/v1',

]

# Set this to the absolute path to the folder (NOT the file!) containing the

# compile_commands.json file to use that instead of 'flags'. See here for

# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html

#

# Most projects will NOT need to set this to anything; you can just change the

# 'flags' list of compilation flags. Notice that YCM itself uses that approach.

compilation_database_folder=''

ifos.path.exists(compilation_database_folder):

database=ycm_core.CompilationDatabase(compilation_database_folder)

else:

database=None

SOURCE_EXTENSIONS=['.cpp','.cxx','.cc','.c','.m','.mm']

def DirectoryOfThisScript():

returnos.path.dirname(os.path.abspath(__file__))

def MakeRelativePathsInFlagsAbsolute(flags,working_directory):

ifnotworking_directory:

returnlist(flags)

new_flags=[]

make_next_absolute=False

path_flags=['-isystem','-I','-iquote','--sysroot=']

forflag inflags:

new_flag=flag

ifmake_next_absolute:

make_next_absolute=False

ifnotflag.startswith('/'):

new_flag=os.path.join(working_directory,flag)

forpath_flag inpath_flags:

ifflag==path_flag:

make_next_absolute=True

break

ifflag.startswith(path_flag):

path=flag[len(path_flag):]

new_flag=path_flag+os.path.join(working_directory,path)

break

ifnew_flag:

new_flags.append(new_flag)

returnnew_flags

def IsHeaderFile(filename):

extension=os.path.splitext(filename)[1]

returnextension in['.h','.hxx','.hpp','.hh']

def GetCompilationInfoForFile(filename):

# The compilation_commands.json file generated by CMake does not have entries

# for header files. So we do our best by asking the db for flags for a

# corresponding source file, if any. If one exists, the flags for that file

# should be good enough.

ifIsHeaderFile(filename):

basename=os.path.splitext(filename)[0]

forextension inSOURCE_EXTENSIONS:

replacement_file=basename+extension

ifos.path.exists(replacement_file):

compilation_info=database.GetCompilationInfoForFile(

replacement_file)

ifcompilation_info.compiler_flags_:

returncompilation_info

returnNone

returndatabase.GetCompilationInfoForFile(filename)

def FlagsForFile(filename,**kwargs):

ifdatabase:

# Bear in mind that compilation_info.compiler_flags_ does NOT return a

# python list, but a "list-like" StringVec object

compilation_info=GetCompilationInfoForFile(filename)

ifnotcompilation_info:

returnNone

final_flags=MakeRelativePathsInFlagsAbsolute(

compilation_info.compiler_flags_,

compilation_info.compiler_working_dir_)

# NOTE: This is just for YouCompleteMe; it's highly likely that your project

# does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR

# ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT.

#try:

#  final_flags.remove( '-stdlib=libc++' )

#except ValueError:

#  pass

else:

relative_to=DirectoryOfThisScript()

final_flags=MakeRelativePathsInFlagsAbsolute(flags,relative_to)

return{

'flags':final_flags,

'do_cache':True

}

YouCompleteMe提供的其他功能

YCM除了提供了基本的补全功能,自动提示错误的功能外,还提供了类似tags的功能:

跳转到定义GoToDefinition

跳转到声明GoToDeclaration

以及两者的合体GoToDefinitionElseDeclaration

可以在.vimrc中配置相应的快捷键。

Shell

nnoremap gl :YcmCompleter GoToDeclaration

nnoremap gf :YcmCompleter GoToDefinition

nnoremap gg :YcmCompleter GoToDefinitionElseDeclaration

1

2

3

nnoremapgl:YcmCompleter GoToDeclaration

nnoremapgf:YcmCompleter GoToDefinition

nnoremapgg:YcmCompleter GoToDefinitionElseDeclaration

另外,YCM也提供了丰富的配置选项,同样在.vimrc中配置。具体请参考

Shell

let g:ycm_error_symbol = '>>'

let g:ycm_warning_symbol = '>*'

1

2

letg:ycm_error_symbol='>>'

letg:ycm_warning_symbol='>*'

同时,YCM可以打开location-list来显示警告和错误的信息:YcmDiags。个人关于ycm的配置如下:

Shell

" for ycm

let g:ycm_error_symbol = '>>'

let g:ycm_warning_symbol = '>*'

nnoremap gl :YcmCompleter GoToDeclaration

nnoremap gf :YcmCompleter GoToDefinition

nnoremap gg :YcmCompleter GoToDefinitionElseDeclaration

nmap :YcmDiags

1

2

3

4

5

6

7

"forycm

letg:ycm_error_symbol='>>'

letg:ycm_warning_symbol='>*'

nnoremapgl:YcmCompleter GoToDeclaration

nnoremapgf:YcmCompleter GoToDefinition

nnoremapgg:YcmCompleter GoToDefinitionElseDeclaration

nmap:YcmDiags

YCM提供的跳跃功能采用了vim的jumplist,往前跳和往后跳的快捷键为Ctrl+O以及Ctrl+I。

总结

YouCompleteMe是我用过的最爽的一个自动补全的插件了。之前使用acp时,遇到大文件基本上就卡死了,以至于都不怎么敢使用。由于YCM使用的时C/S结构,部分使用vim脚本编写,部分认为原生代码,使得跑起来速度飞快。

抛弃Vim自带的坑爹的补全吧,抛弃ctags吧,抛弃cscope吧,YCM才是终极的补全神器。

在安装过程中,我也遇到了不少的坑。一会会发一篇解决这些坑的文章。

最后祝大家码年顺利,一码平川,码到功成。

vim插件自动补齐_(转)Vim自动补全神器:YouCompleteMe相关推荐

  1. vim插件自动补齐_给VIM添加REPL

    REPL: 读取-求值-输出"循环(英语:Read-Eval-Print Loop,简称REPL)是一个简单的,交互式的编程环境. python作为一个动态语言,REPL在开发过程中起到了很 ...

  2. Vim自动补全神器YouCompleteMe的配置

    简介:YouCompleteMe号称Vim的自动补全神器,该项目在github的地址:YouCompleteMe:以下在10.0.1 build-1379776平台配置完成 插件安装操作: 1.确保V ...

  3. vim插件快速配置使用(自己的vim插件配置)

    文章目录 说明 1. 插件管理插件安装和使用(vim-plug) 2.插件使用方法 3.主题 4.额外的 将下面的内容,粘贴到~/.vimrc文件中,在按照使用方法来安装和配置即可. let g:ma ...

  4. linux快捷命令补齐,Linux Shell简介——自动补齐/命令行的历史记录/编辑命令行/可用的 Shell 快捷方式.doc...

    Linux Shell简介--自动补齐/命令行的历史记录/编辑命令行/可用的 Shell 快捷方式 Unix (及后继者 Linux)在命令行下面诞生,因此,Unix 中的命令行有许多非常实用的功能. ...

  5. 自动驾驶芯片_盘点全球自动驾驶芯片“战场”参与者

    据了解,目前出货量最大的驾驶辅助芯片厂商Mobileye.Nvidia形成"双雄争霸"局面,Xilinx则在FPGA的路线上进军,Google.地平线.寒武纪向专用领域AI芯片发力 ...

  6. 五级自动驾驶分级_关于确保自动驾驶汽车安全的五件事

    五级自动驾驶分级 乔纳森·奥卡拉汉(Jonathan O'Callaghan)(by Jonathan O'Callaghan) Self-driving cars, or connected and ...

  7. 苹果 python蚂蚁森林自动收能量_蚂蚁森林自动收取能量、偷取能量、浇水(使用adb、python)...

    涉及到的技术: 1.python 2.adb 具备的功能: 1.自动收取能量 2.自动偷取能量 3.自动给指定的朋友浇水 使用方法: 1.打开电脑,USB线一头接手机,一头接电脑. 2.电脑运行pyt ...

  8. 在vim中写python程序_用 Vim 写 Python 的最佳实践是什么?

    先来晒个图:语法检查 如果用 vim8, 那么可以用异步检测的 w0rp/ale 代替 syntastic 了,再也不用羡慕 flycheck, 也不用因为语法检查而卡顿了. 关于 ale 这部分的个 ...

  9. vim java开发环境配置_搭建vim作为java开发环境(-)

    说明:本文的内容作为自己搭建环境的记录,内容基本是从网上查找来的,所以原作者看了不要太介意.另外本人是Mac电脑,请参照者注意了. javacomplete:是在vim开发中提供提示效果的插件. 1. ...

最新文章

  1. Glide 加载图片不显示(Android9.0无法加载图片)
  2. Android Cursor自动更新的实现和原理
  3. iOS 获取appstore 版本号
  4. python输入输出有问题_使用pySerial从Python获取输入/输出错误
  5. xp系统桌面计算机不见了怎么办,XP系统的垃圾箱在桌面上不见了!怎么处理?
  6. 分布式锁是啥?zk还是redis?
  7. React中useEffect使用
  8. 红米note3支持html,红米note3如何检测硬件信息?指令代码说明
  9. Redis数据结构总结
  10. 用JavaScript替换重复字符
  11. 轻便型面部捕捉,一个APP就搞定!
  12. 华为云会议的前世今生
  13. composer设置国内源
  14. 用混合编程实现两个LED交替闪烁
  15. android native 代码内存泄露 定位方案
  16. interrupt、interrupted 、isInterrupted 详解04
  17. border-radius的一种经典使用(上凸边框)
  18. 今日芯声 | 一张壁纸!让你的小米MIX 3华丽变身“MIX Alpha”
  19. 修改CMD窗口 使其翻阅之前的内容
  20. 我国量子计算机 图片,Origin Q一周速览:国内首个量子计算生物化学行业应用生态联盟成立...

热门文章

  1. 今日头条适配方案使用
  2. 大数据学习日常小练习题汇总收纳
  3. 微信大更新,电脑也可以刷朋友圈了!
  4. UOJ#8. Quine
  5. Cadence virtuoso 常用快捷键汇总
  6. 真相只有一个!厉害了,用 IDEA 神器看源码,效率真高!
  7. endonte 重新编号_endnote参考文献编号连续 用endnote设置引用文献格式,连续引用时默认是[1-5],怎么改成][1]-[5]?...
  8. 非人学园一直显示服务器加载,非人学园(日韩服)总是显示无法连接网络
  9. springAOP事物管理不生效原因总结————转载收藏于: superdog007
  10. 深度学习之人物年龄预测