jEdit應用指南【基礎篇】
創作時間:2005年9月24日
序
jEdit是一個非常強大和靈活的文本編輯器.在java開發過程中,我一直使用eclipse,UltraEdit和jEdit.經常在它們之間來回切換.因為ultraEdit太簡單,而eclipse又太復雜,所以現在我要介紹的就是簡單又復雜的jEdit,它將大大加速你的編程,我會將重點放在其內嵌的Beanshell腳本上。
第一章 jEdit是Java編寫,強大,易用的程序員文本編輯器
以下部分介紹是我從其官方網站翻譯來的:
jEdit是一個成熟的,設計優秀的程序員文本編輯器,已經有了7年的開發歷史。在功能和易用性方面壓倒許多昂貴的開發工具時,jEdit在GNU公用許可證(GPL)下發布成了開源軟件。
jEdit的核心主要由Slava Pestov開發完成,一支由世界各地的程序員組成的隊伍正在為jEdit開發插件(plugin)。
下面是jEdit的幾個特色:
- 用java編寫,所以它可以運行在Mac OS X, OS/2, Unix, VMS 和Windows平臺上(山顛:非java程序員不推薦使用)
- 內建宏語言;可擴展的插件體系;目前已經有了很多宏和插件.(山顛:內建BeanShell腳本語言,通過插件可以支持其他腳本語言.這點是我之所以在這里費力的原因 ^_^)
- 使用jEdit的插件管理器可以下載插件并安裝.(山顛:如果網絡狀況允許,這個功能確實非常好.不過建議想這么干的家伙去sf看看那些插件都是干什么的先,全裝了會影響性能)
- 提供超過130總編程語言的自動縮進和語法高亮.(山顛:很棒.據我所知,BeanShell的高亮顯示好象只有它支持)
- 支持UTF8和Unicode在內的大量字符編碼
- 代碼折疊
- 自動換行
- 極高的可配置性和可定制性
- 所有其他你希望在一個文本編輯器里找到的功能,不管是基礎性的還是高級的,你都可以在jEdit中找到.請查看全部功能清單
看看這些截圖,從直觀上感受一下jEdit:http://www.jedit.org/index.php?page=screenshots
是啊,千變萬化的jEdit。融合VIM,EditPlus,Emacs等編輯器的優點于一身。請查看維基百科中的文本編輯器比較。在這個有些片面(顯然測試的是個陽春版本,沒有加任何插件)的比較中,jEdit的表現仍然很是搶眼,全面超越它的只有Emacs(這個超級難用的程序)。作為一個Java程序員,我找遍了整個地球,在苦惱地承認自己的智商還不足以輕松學好Emacs或Vim后欣喜地發現了:開源、強大、易用、Java編寫的jEdit正是我要的。
相關:從其他編輯器轉移到jEdit http://community.jedit.org/cgi-bin/TWiki/view/Main/SwitchingToJEdit
第二章 jEdit的下載、安裝和插件配置
jEdit的官方主頁是www.jedit.org,目前最高版本是4.3,穩定版本是4.2final。因為有些插件還不支持4.3,因此建議下載jEdit4.2版本。jEdit還需要JDK1.4的支持
Note:jEdit的各個版本都有平臺獨立的版本和相應平臺的版本。不過針對windows用戶,jEdit還提供了一個啟動器jEditLauncher。(目前官方已經不提供啟動器了,相關的討論見:http://community.jedit.org/?q=node/view/1411,其實以前的啟動程序還是能用的,下載我使用的啟動程序包,釋放到jedit安裝目錄下就行了)
安裝完jEdit,下一步就是安裝插件。和Eclipse類似,jEdit的插件安裝也有兩種途徑:直接在jEdit中升級和手工下載插件包。建議選擇直接升級。
1. 直接升級。
按Plugins->Plugin Manager打開插件管理器,進入Install,選擇你想裝的插件,點擊install就可以安裝了。注意,一次安裝不要選中太多插件,否則這個過程將持續很長時間。安裝完成后可以在Plugins->Plugin Options中進行配置。
2. 手工安裝
jEdit插件是個開源項目,見http://sourceforge.net/projects/jedit-plugins/
在官方主頁上也有這些插件的介紹:http://plugins.jedit.org/list.php。仔細的看看插件的說明,確定你需要的。下載后把壓縮包后解壓縮到jEdit安裝目錄的jars目錄中(確保有jar文件在jars目錄下,如果你下載的是完全版的插件,jars目錄下還會有個包含源文件的同名文件夾),之后重啟jEdit。
Note:必備的幾個美化界面的插件是:Buffer Tabs(類似UltraEdit的標簽)、Background(為View――編輯區添加背景圖片)、LookAndFeel(外觀選擇)。如果有需要,其他插件會在后續文章中按用途進行介紹。
第三章 Beanshell腳本在jEdit的應用
第一節 強大、簡單、獨到的宏
在目前的Java IDE領域中,Eclipse是最好的。但jEdit并不是一個IDE,而是“程序員文本編輯器”。在文本編輯領域,jEdit擁有很多獨到的優勢,其中之一,也是作者最感興趣的部分,就是它的宏——其實就是Beanshell腳本。內嵌的Beanshell引擎能夠直接訪問jEdit的內部對象和API,例如:你可以寫出這樣的宏命令:
buffer.undo(textArea); //撤銷當前buffer的一個操作
Registers.paste(textArea,'$',false);//粘貼到當前文本域
textArea.setSelectedText(" ");//將選定文本設為“ ”
textArea.goToNextLine(false);//移動光標到下一行
Registers.copy(textArea,'$');//copy
textArea.showWordCountDialog();//顯示對話框,統計字數
textArea.backspace();//按一下后退鍵
buffer、textArea都是jEdit的內部對象,Registers是jEdit中的寄存器類。可見Beanshell腳本具有直接訪問jEdit內部資源的能力,這使我們寫出一個高度自動化的宏命令成為可能。
除了手工編寫宏文件(.bsh文件)外,jEdit也可以錄制宏。 錄制宏有三種途徑:
1.使用菜單:打開 Macros->Record Macro,進行操作,完成時點擊stop Recording。
2.使用快捷鍵:開始錄制用c+m c+r,結束錄制用c+m c+s。(其中c+m c+r表示先按Ctrl+e,再按Ctrl+r,也可以按住Ctrl,然后再接著按m和r鍵)
3.使用action bar:Ctrl+Enter組合鍵打開action bar,輸入record,按Tab鍵,回車,就開始錄制宏。完成后打開action bar,輸入recording,按tab,回車。
Note:多種使用方式體現出jEdit強大的操作性;有關action bar的相關資料,請查看幫助。
Note:宏文件必須存放在jedit\macros\目錄或\Documents and Settings\uername\.jedit\macros目錄下,前者是系統宏目錄,后者是用戶宏目錄。
第二節 使用 jEdit中的Beanshell編寫宏
到了這一步,看來我們又要學一門新的語言了。“太麻煩了!”,你可能已經決定放棄jEdit了。幸好,Beanshell是Java陣營的腳本語言,我們基本上不需要什么精力就學會怎么在jEdit中使用它——當然前提你必須熟悉Java,這就是我在前面推薦Java程序員使用jEdit的原因。
Beanshell 有腳本語言的特性,如弱類型、閉包等,但同時也完全兼容Java語法。為了簡便起見,我們這里就象java一樣來寫beanshell,只要記住一點:它是解釋執行的。更深入的學習推薦訪問以下網站:
1. http://dev.csdn.net/develop/article/15/15090.shtm
2. http://www-128.ibm.com/developerworks/cn/java/l-beanshell/index.html
3. 官方網站:http://www.beanshell.org
4. 在線教程:http://www.beanshell.org/manual/contents.html
下面通過jEdit自帶的一個宏文件來看看宏是怎么“煉成”的。
實例:jEdit 4.2\macros\java\Java_File_Save.bsh
文件源代碼如下:中文部分是添加的注釋

/**//*
* Java_File_Save.bsh - a BeanShell macro for saving new java files.
*
* Copyright (C) 2004 Nicholas O'Leary nol@deferential.net
*
* :mode=beanshell:tabSize=3:indentSize=3:maxLineLen=0:noTabs=true:
* :indentOnTab=true:indentOnEnter=true:folding=explicit:collapseFolds=1:
*
*
* Notes:
* Only the first 250 lines of the buffer are scanned for a suitable
* class or interface declaration.
*
* Changes:
* 17-May-04: Only scans if the edit mode is either 'java' or the default mode
* : Ignores declarations that are in multiline comments
* 08-Jun-04: If an infinite loop is hit (1000 iterations) in the comment
* : parsing, it now opens the default save dialog, rather than
* : just returning.
* $Id: Java_File_Save.bsh,v 1.1 2004/06/26 19:10:58 spestov Exp $
*/
//以上是宏作者寫的說明

// Check this is a new file。
// 在jEdit中buffer對象指向當前正在編輯的文件,打開一個文件,就是在當前視圖(view)的textArea中創建一個buffer
// 在幫助中可以查看這些類的API:對象buffer: org.gjt.sp.jedit.Buffer,
// 對象textArea: org.gjt.sp.jedit.textarea.JEditTextArea
// 對象view: org.gjt.sp.jedit.View
// beanshell能訪問的內存中的對象有view,buffer,textArea,editPane,wm,scriptPath,
// 詳情請看幫助中的 Chapter 13. Macro Basics-->Predefined Variables in BeanShell小節
if (buffer.isNewFile() && buffer.getPath() != null)


{
// Only look further if the mode is 'java', or still the default
String buffer_mode = buffer.getMode().toString();//編輯模式,jEdit的默認編輯模式是text
if (buffer_mode.equals("java") || buffer_mode.equals(jEdit.getProperty("buffer.defaultMode","")))

{
String fullpath = buffer.getPath();//打開文件的路徑
VFS vfs = VFSManager.getVFSForPath(fullpath);//根據路徑生成虛擬文件系統
// Split into constituent parts
String path = vfs.getParentOfPath(fullpath);//獲得所在目錄
String name = vfs.getFileName(fullpath);//獲得文件名
// At most, check the first 250 lines - this sounds reasonable to me
//以下利用GNU的正則表達式包檢查代碼,提取出類名(最多檢查250行)
int maxLine = Math.min(buffer.getLineCount(),250);
import gnu.regexp.RE;
import gnu.regexp.REMatch;//這樣引入包,jar文件必須能被jEdit找到(只要將jar文件放在jars目錄下)
// Build the regex - based on the offical java language spec.
RE regex = new RE("^\\s*(public|protected|private|static|abstract|final|native|synchronized|transient|volatile|strictfp)?\\s*(class|interface)\\s*([^ {/]*)");
int regexMinimum = regex.getMinimumLength();//可能構成一次匹配的最小字符數
boolean inComment = false;//是否在注釋里
for(int i=0;i<maxLine;i++)

{
String txt = buffer.getLineText(i);//第i行的字符串
int count = 0;
// See if this line has a the start or finish of a multiline comment
//確定提取的類名是有效的,不在注釋里
while (txt.indexOf("/*")!=-1 || txt.indexOf("*/")!=-1)

{
// A little paranoia on my part
count++;
if (count==1000)//最多執行1000次,如果這行長度超過2000就不管了,直接保存為默認文件名

{
Log.log(Log.ERROR,BeanShell.class,"Infinite loop:["+txt+"]");
//log: org.gjt.sp.util.Log jEdit的log系統
buffer.save(view,null,true);//以默認名保存
return;//結束腳本執行
}
// Look for the next starting comment if we're not in a comment
if (!inComment)

{
int commentStartIndex = txt.indexOf("/*");
if (commentStartIndex != -1)

{
inComment = true;
if (commentStartIndex+2 == txt.length())
txt = "";
else
txt = txt.substring(commentStartIndex+2);
}
}
// Look for the next ending comment if we are in a comment
if (inComment)

{
int commentEndIndex = txt.indexOf("*/");
if (commentEndIndex != -1)

{
inComment = false;
if (commentEndIndex+2 == txt.length())
txt = "";
else
txt = txt.substring(commentEndIndex+2);

} else
{
continue;
}
}
}
// We now know if the remainder of the line is in a comment or not
if (!inComment)

{
// Ignore lines that are too short for the regex
if (txt.length() < regexMinimum)
continue;
REMatch match = regex.getMatch(txt);
// See if it matches
if (match!=null)

{
int startIndex = match.getStartIndex(3);
int endIndex = match.getEndIndex(3);
// Extract the class/interface name 得出第三個匹配,就是類名
name = txt.substring(startIndex,endIndex)+".java";//文件名
break;
}
}
}
// Open the VFSBrowser
String[] files = GUIUtilities.showVFSFileDialog(view,path+name,
VFSBrowser.SAVE_DIALOG,false);
if(files == null)
return false;
buffer.save(view,files[0],true);
return;
}
}

// This isn't a file that has been scanned, so just do a normal save
buffer.save(view,null,true);


/**//*

Macro index data (in DocBook format)

<listitem>
<para><filename>Java_File_Save.bsh</filename></para>
<abstract><para>Acts as a wrapper script to the Save As action. If the buffer
is a new file, it scans the first 250 lines for a Java class or interface
declaration. On finding one, it extracts the appropriate filename to be
used in the Save As dialog.</para></abstract>
</listitem>

*/