001/*
002 * (C) Copyright 2006-2010 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     bstefanescu
018 */
019package org.nuxeo.shell.swing;
020
021import javax.swing.text.BadLocationException;
022
023/**
024 * The last line in the console - where the user type the commands. Must be instantiated each time a new line is used.
025 * (after CRLF)
026 *
027 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
028 */
029public class CmdLine {
030
031    protected int index;
032
033    protected int start;
034
035    protected String prompt;
036
037    protected int cmdStart;
038
039    protected Console console;
040
041    public CmdLine(Console console) {
042        try {
043            this.console = console;
044            this.index = console.getLineCount() - 1;
045            start = console.getLineStartOffset(index);
046            prompt = console.reader.getDefaultPrompt();
047            cmdStart = start + prompt.length();
048        } catch (Exception e) {
049            throw new RuntimeException(e);
050        }
051    }
052
053    public int getIndex() {
054        return index;
055    }
056
057    public int getStart() {
058        return start;
059    }
060
061    public int getCmdStart() {
062        return cmdStart;
063    }
064
065    public int getEnd() {
066        try {
067            return console.getLineEndOffset(index);
068        } catch (BadLocationException e) {
069            throw new RuntimeException(e);
070        }
071    }
072
073    public String getLineText() {
074        try {
075            return console.getDocument().getText(start, getEnd() - start);
076        } catch (BadLocationException e) {
077            throw new RuntimeException(e);
078        }
079    }
080
081    public String getPrompt() {
082        return prompt;
083    }
084
085    /**
086     * Get the caret position relative to the beginning of the command text (see getCmdStart())
087     *
088     * @return
089     */
090    public int getLocalCaretPosition() {
091        int cp = console.getCaretPosition() - cmdStart;
092        return cp < 0 ? 0 : cp;
093    }
094
095    public String getText() {
096        try {
097            return console.getDocument().getText(cmdStart, getEnd() - cmdStart);
098        } catch (BadLocationException e) {
099            throw new RuntimeException("Failed to get line text", e);
100        }
101    }
102
103    public void setText(String text) {
104        int end = getEnd();
105        console.replaceRange(text, cmdStart, end);
106        console.setCaretPosition(console.getDocument().getLength());
107    }
108
109    public void setTextFromCaret(String text) {
110        int end = getEnd();
111        console.replaceRange(text, console.getCaretPosition(), end);
112        console.setCaretPosition(end);
113    }
114
115    public void write(String text) {
116        int cp = console.getCaretPosition();
117        int end = getEnd();
118        int len = text.length();
119        if (cp < end) {
120            int e = cp + len;
121            if (e > end) {
122                console.replaceRange(text, cp, end);
123            } else {
124                console.replaceRange(text, cp, e);
125            }
126        } else {
127            console.insert(text, cp);
128        }
129        console.setCaretPosition(cp + len);
130        // console.repaint();
131    }
132
133    public void sync() {
134        StringBuffer sb = console.reader.getCursorBuffer().getBuffer();
135        sb.setLength(0);
136        sb.append(getText());
137        console.reader.getCursorBuffer().cursor = getLocalCaretPosition();
138    }
139
140    public void rsync() {
141        setText(console.reader.getCursorBuffer().getBuffer().toString());
142        console.setCaretPosition(cmdStart + console.reader.getCursorBuffer().cursor);
143    }
144
145    public boolean canMoveCaret(int where) {
146        int cp = console.getCaretPosition() + where;
147        return cp >= cmdStart && cp <= getEnd();
148    }
149
150    public int setCompletionWord(String word) {
151        int p = getLocalCaretPosition();
152        String text = getText();
153        Word w = getWord(text, p);
154        // replace w with word
155        int ws = cmdStart + w.index;
156        int we = ws + w.length();
157        console.replaceRange(word, ws, we);
158        console.setCaretPosition(ws + word.length());
159        return getLocalCaretPosition();
160    }
161
162    /**
163     * Get the word from the command line which is near the given relative caret position. Used for completion.
164     *
165     * @param pos
166     * @return
167     */
168    public Word getWord(String text, int pos) {
169        if (text.length() == 0) {
170            return new Word("", 0);
171        }
172        if (pos <= 0) {
173            // get next word
174            int i = text.indexOf(' ');
175            String w = i <= 0 ? "" : text.substring(0, i);
176            return new Word(w, 0);
177        }
178        // get the previous word.
179        int i = text.lastIndexOf(' ', pos);
180        if (i == -1) {
181            i = 0;
182            int e = text.indexOf(' ');
183            if (e == -1) {
184                return new Word(text, 0);
185            } else {
186                return new Word(text.substring(0, e), 0);
187            }
188        } else {
189            i++;
190            int e = text.indexOf(' ', i);
191            if (e == -1) {
192                return new Word(text.substring(i), i);
193            } else {
194                return new Word(text.substring(i, e), i);
195            }
196        }
197    }
198
199    static class Word {
200        public int index;
201
202        public String text;
203
204        public Word(String text, int index) {
205            this.text = text;
206            this.index = index;
207        }
208
209        public int length() {
210            return text.length();
211        }
212
213        @Override
214        public String toString() {
215            return text + " [" + index + "]";
216        }
217    }
218}