001 /* 002 * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved. 003 * 004 * This software is distributable under the BSD license. See the terms of the 005 * BSD license in the documentation provided with this software. 006 */ 007 package jline; 008 009 import java.io.*; 010 import java.util.*; 011 012 /** 013 * <p> 014 * A simple {@link Completor} implementation that handles a pre-defined 015 * list of completion words. 016 * </p> 017 * 018 * <p> 019 * Example usage: 020 * </p> 021 * <pre> 022 * myConsoleReader.addCompletor (new SimpleCompletor (new String [] { "now", "yesterday", "tomorrow" })); 023 * </pre> 024 * 025 * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a> 026 */ 027 public class SimpleCompletor implements Completor, Cloneable { 028 /** 029 * The list of candidates that will be completed. 030 */ 031 SortedSet candidates; 032 033 /** 034 * A delimiter to use to qualify completions. 035 */ 036 String delimiter; 037 final SimpleCompletorFilter filter; 038 039 /** 040 * Create a new SimpleCompletor with a single possible completion 041 * values. 042 */ 043 public SimpleCompletor(final String candidateString) { 044 this(new String[] { 045 candidateString 046 }); 047 } 048 049 /** 050 * Create a new SimpleCompletor with a list of possible completion 051 * values. 052 */ 053 public SimpleCompletor(final String[] candidateStrings) { 054 this(candidateStrings, null); 055 } 056 057 public SimpleCompletor(final String[] strings, 058 final SimpleCompletorFilter filter) { 059 this.filter = filter; 060 setCandidateStrings(strings); 061 } 062 063 /** 064 * Complete candidates using the contents of the specified Reader. 065 */ 066 public SimpleCompletor(final Reader reader) throws IOException { 067 this(getStrings(reader)); 068 } 069 070 /** 071 * Complete candidates using the whitespearated values in 072 * read from the specified Reader. 073 */ 074 public SimpleCompletor(final InputStream in) throws IOException { 075 this(getStrings(new InputStreamReader(in))); 076 } 077 078 private static String[] getStrings(final Reader in) 079 throws IOException { 080 final Reader reader = 081 (in instanceof BufferedReader) ? in : new BufferedReader(in); 082 083 List words = new LinkedList(); 084 String line; 085 086 while ((line = ((BufferedReader) reader).readLine()) != null) { 087 for (StringTokenizer tok = new StringTokenizer(line); 088 tok.hasMoreTokens(); words.add(tok.nextToken())) { 089 ; 090 } 091 } 092 093 return (String[]) words.toArray(new String[words.size()]); 094 } 095 096 public int complete(final String buffer, final int cursor, final List clist) { 097 String start = (buffer == null) ? "" : buffer; 098 099 SortedSet matches = candidates.tailSet(start); 100 101 for (Iterator i = matches.iterator(); i.hasNext();) { 102 String can = (String) i.next(); 103 104 if (!(can.startsWith(start))) { 105 break; 106 } 107 108 if (delimiter != null) { 109 int index = can.indexOf(delimiter, cursor); 110 111 if (index != -1) { 112 can = can.substring(0, index + 1); 113 } 114 } 115 116 clist.add(can); 117 } 118 119 if (clist.size() == 1) { 120 clist.set(0, ((String) clist.get(0)) + " "); 121 } 122 123 // the index of the completion is always from the beginning of 124 // the buffer. 125 return (clist.size() == 0) ? (-1) : 0; 126 } 127 128 public void setDelimiter(final String delimiter) { 129 this.delimiter = delimiter; 130 } 131 132 public String getDelimiter() { 133 return this.delimiter; 134 } 135 136 public void setCandidates(final SortedSet candidates) { 137 if (filter != null) { 138 TreeSet filtered = new TreeSet(); 139 140 for (Iterator i = candidates.iterator(); i.hasNext();) { 141 String element = (String) i.next(); 142 element = filter.filter(element); 143 144 if (element != null) { 145 filtered.add(element); 146 } 147 } 148 149 this.candidates = filtered; 150 } else { 151 this.candidates = candidates; 152 } 153 } 154 155 public SortedSet getCandidates() { 156 return Collections.unmodifiableSortedSet(this.candidates); 157 } 158 159 public void setCandidateStrings(final String[] strings) { 160 setCandidates(new TreeSet(Arrays.asList(strings))); 161 } 162 163 public void addCandidateString(final String candidateString) { 164 final String string = 165 (filter == null) ? candidateString : filter.filter(candidateString); 166 167 if (string != null) { 168 candidates.add(string); 169 } 170 } 171 172 public Object clone() throws CloneNotSupportedException { 173 return super.clone(); 174 } 175 176 /** 177 * Filter for elements in the completor. 178 * 179 * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a> 180 */ 181 public static interface SimpleCompletorFilter { 182 /** 183 * Filter the specified String. To not filter it, return the 184 * same String as the parameter. To exclude it, return null. 185 */ 186 public String filter(String element); 187 } 188 189 public static class NoOpFilter implements SimpleCompletorFilter { 190 public String filter(final String element) { 191 return element; 192 } 193 } 194 }