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