当前位置: 首页 > 工具软件 > JLine > 使用案例 >

Jline中自定义自动补全功能的实现

商柏
2023-12-01

    Jline是一个开源的Java控制台输入类库,最近的项目需要用到这个东东(Zookeeper的命令行用的也是这个),就是实现在命令行输入SQL语句,并解析它。不过它自带的自动补全功能有点弱,无法满足输入SQL时的TAB提示(提示SQL的关键字、表名、字段名之类的)的需求,下面贴出我的实现,本人使用的版本是0.9.94。

    要实现TAB提示,需要实现Jline的Completor接口,其核心方法是complete方法,方法原型是这样的,

    

public int complete(final String buffer, final int cursor, final List clist)

   

      参数解释:String buffer --- 在控制台按下tab键时已经输入的字符串

                      int cursor --- 在控制台按下tab键时光标的位置

                      List clist --- 返回的候选词

    下面是我的代码   

package client.shell;

import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import jline.Completor;

public class MyCompletor implements Completor, Cloneable {
	SortedSet candidates;

	public MyCompletor(final String[] candidateStrings) {
		candidates = new TreeSet();
		for (String string : candidateStrings) {
			candidates.add(string);
		}
	}

	public int complete(final String buffer, final int cursor, final List clist) {
		String start = (buffer == null) ? "" : buffer;
		// 找到字符串中最后一个空格出现的位置
		int index = start.lastIndexOf(" ");
		// 把最后一个空格后面的词截出来
		String tmp = start.substring(index + 1, start.length());
		// candidates中存储的词都是按字典序排下来的
		// 例如candidates中有如下三个词:insert select where
		// 如果tmp是'se',则通过下面的tailSet方法,会返回select和where两个词
		SortedSet matches = candidates.tailSet(tmp);
		for (Iterator i = matches.iterator(); i.hasNext();) {
			String can = (String) i.next();
			// 过滤掉不是以tmp这个字符串开头的词
			if (!(can.startsWith(tmp))) {
				break;
			}
			clist.add(can);
		}
		if (clist.size() == 1) {
			clist.set(0, ((String) clist.get(0)) + " ");
		}
		// the index of the completion is always from the beginning of the
		// buffer.
		// 如果没有从候选词中找到任何匹配的词,则返回-1
		// 如果index为-1,即输入的字符串中没有空格,则返回0(起始位置)
		// 如果index不是-1,则返回最后一个空格的位置加1
		return (clist.size() == 0) ? (-1) : (index == -1 ? 0 : index + 1);
	}

	public void setCandidates(final SortedSet candidates) {
		this.candidates = candidates;
	}

	public SortedSet getCandidates() {
		return Collections.unmodifiableSortedSet(this.candidates);
	}

	public void setCandidateStrings(final String[] strings) {
		setCandidates(new TreeSet(Arrays.asList(strings)));
	}

	public void addCandidateString(final String candidateString) {
		candidates.add(candidateString);
	}

	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}

    不过在使用中还是有几个问题还没解决,比如按HOME和END键没有返回行首或行尾,有时候按方向键上翻历史记录时,导致前面已经输出的多个字符被历史记录覆盖掉了,这两个问题都是用XShell远程连接时才有的,直接用键盘连机器还没有出现这些问题呀。。。如果哪位大神知晓其中缘由,请下方回复,不胜感激。

 类似资料: