001package com.ganteater.ae.desktop.editor;
002
003import java.awt.BorderLayout;
004import java.awt.Dimension;
005import java.awt.FileDialog;
006import java.awt.Point;
007import java.awt.event.ActionEvent;
008import java.awt.event.ActionListener;
009import java.awt.event.FocusAdapter;
010import java.awt.event.FocusEvent;
011import java.awt.event.KeyAdapter;
012import java.awt.event.KeyEvent;
013import java.awt.event.MouseAdapter;
014import java.awt.event.MouseEvent;
015import java.util.ArrayList;
016import java.util.Arrays;
017import java.util.Comparator;
018import java.util.HashMap;
019import java.util.List;
020import java.util.Map;
021import java.util.Properties;
022import java.util.Set;
023import java.util.StringTokenizer;
024import java.util.stream.Collectors;
025
026import javax.swing.DefaultListModel;
027import javax.swing.JList;
028import javax.swing.JMenuItem;
029import javax.swing.JOptionPane;
030import javax.swing.JRootPane;
031import javax.swing.JScrollPane;
032import javax.swing.SwingUtilities;
033import javax.swing.event.ListSelectionEvent;
034import javax.swing.event.ListSelectionListener;
035import javax.swing.text.BadLocationException;
036
037import org.apache.commons.lang.StringEscapeUtils;
038import org.apache.commons.lang3.StringUtils;
039
040import com.ganteater.ae.AEWorkspace;
041import com.ganteater.ae.OperationHolder;
042import com.ganteater.ae.TaskCancelingException;
043import com.ganteater.ae.desktop.ui.DialogPopupMenu;
044import com.ganteater.ae.desktop.ui.OptionPane;
045import com.ganteater.ae.desktop.view.View;
046import com.ganteater.ae.processor.BaseProcessor;
047import com.ganteater.ae.processor.CommandInfo;
048import com.ganteater.ae.processor.Processor;
049import com.ganteater.ae.util.ClassUtils;
050import com.ganteater.ae.util.xml.easyparser.EasyParser;
051import com.ganteater.ae.util.xml.easyparser.Node;
052
053public class CommandHelperDialog extends HelperDialog {
054
055        private static final long serialVersionUID = 1L;
056
057        private DefaultListModel<String> commandListModel = new DefaultListModel<>();
058        private JList<String> commands = new JList<String>(commandListModel);
059
060        private DefaultListModel<String> examplesListModel = new DefaultListModel<>();
061        private JList<String> examples = new JList<String>(examplesListModel);
062
063        private String startSymbols;
064
065        private Map<String, List<String>> exampleMap = new HashMap<>();
066
067        public CommandHelperDialog(CodeHelper codeHelper) {
068                super(codeHelper);
069
070                setAlwaysOnTop(true);
071                setUndecorated(true);
072                JScrollPane comp = new JScrollPane(commands);
073                comp.setPreferredSize(new Dimension(150, 200));
074
075                getContentPane().add(comp, BorderLayout.WEST);
076
077                commands.setBackground(getBackground());
078                commands.addFocusListener(new FocusAdapter() {
079                        @Override
080                        public void focusLost(FocusEvent e) {
081                                if (e.getOppositeComponent() != CommandHelperDialog.this && e.getOppositeComponent() != examples) {
082                                        setVisible(false);
083                                }
084                        }
085                });
086                commands.addMouseListener(new MouseAdapter() {
087                        @Override
088                        public void mouseClicked(MouseEvent e) {
089                                String commandName = commands.getSelectedValue();
090                                if (e.getClickCount() == 2) {
091                                        if (examples.getModel().getSize() > 1) {
092                                                if (examples.isSelectionEmpty()) {
093                                                        examples.requestFocus();
094                                                        examples.setSelectedIndex(0);
095                                                } else {
096                                                        perform(commandName);
097                                                }
098                                        } else {
099                                                perform(commandName);
100                                        }
101                                } else {
102                                        fillExamples(commandName);
103                                }
104                        }
105                });
106                commands.addListSelectionListener(new ListSelectionListener() {
107                        @Override
108                        public void valueChanged(ListSelectionEvent e) {
109                                String commandName = commands.getSelectedValue();
110                                fillExamples(commandName);
111                        }
112                });
113                commands.addKeyListener(new KeyAdapter() {
114                        @Override
115                        public void keyPressed(KeyEvent e) {
116                                int keyCode = e.getKeyCode();
117                                if (keyCode == KeyEvent.VK_ESCAPE) {
118                                        setVisible(false);
119                                } else {
120                                        if (keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_ENTER) {
121                                                if (examples.getModel().getSize() > 1) {
122                                                        examples.requestFocus();
123                                                        examples.setSelectedIndex(0);
124                                                } else {
125                                                        String commandName = commands.getSelectedValue();
126                                                        perform(commandName);
127                                                }
128                                        }
129                                }
130                        }
131                });
132
133                JScrollPane comp1 = new JScrollPane(examples);
134                comp1.setPreferredSize(new Dimension(400, 200));
135
136                getContentPane().add(comp1, BorderLayout.CENTER);
137
138                examples.setBackground(getBackground());
139                examples.addMouseListener(new MouseAdapter() {
140                        @Override
141                        public void mouseClicked(MouseEvent e) {
142                                String commandName = examples.getSelectedValue();
143                                if (e.getClickCount() == 2) {
144                                        perform(commandName);
145                                }
146                        }
147                });
148                examples.addFocusListener(new FocusAdapter() {
149                        @Override
150                        public void focusLost(FocusEvent e) {
151                                if (e.getOppositeComponent() != CommandHelperDialog.this && e.getOppositeComponent() != commands) {
152                                        setVisible(false);
153                                }
154                        }
155                });
156                examples.addKeyListener(new KeyAdapter() {
157                        @Override
158                        public void keyPressed(KeyEvent e) {
159                                int keyCode = e.getKeyCode();
160                                if (keyCode == KeyEvent.VK_ESCAPE) {
161                                        setVisible(false);
162                                } else {
163                                        if (keyCode == KeyEvent.VK_ENTER) {
164                                                String commandName = examples.getSelectedValue();
165                                                perform(commandName);
166                                        } else if (keyCode == KeyEvent.VK_LEFT) {
167                                                commands.requestFocus();
168                                        }
169                                }
170                        }
171                });
172
173        }
174
175        private void perform(String commandName) {
176                List<String> examples = exampleMap.get(commandName);
177                setVisible(false);
178                if (examples != null && !examples.isEmpty()) {
179                        int selectedIndex = this.examples.getSelectedIndex();
180                        if (selectedIndex < 0) {
181                                selectedIndex = 0;
182                        }
183
184                        String text = examples.get(selectedIndex);
185                        if (!StringUtils.startsWith(text, "<") && StringUtils.contains(text, ":")) {
186                                text = StringUtils.substringAfter(text, ":");
187                        }
188                        insertTag(startSymbols, text);
189                }
190                if (examples == null) {
191                        commandName = commandName.trim();
192                        if (!StringUtils.startsWith(commandName, "<") && StringUtils.contains(commandName, ":")) {
193                                commandName = StringUtils.substringAfter(commandName, ":");
194                        }
195                        insertTag(startSymbols, commandName);
196                }
197        }
198
199        private void fillExamples(String commandName) {
200                List<String> list = exampleMap.get(commandName);
201                if (list != null) {
202                        examplesListModel.removeAllElements();
203                        for (String example : list) {
204                                examplesListModel.addElement(example);
205                        }
206                        if (!list.isEmpty()) {
207                                examples.setSelectedIndex(0);
208                        }
209                }
210        }
211
212        public void fillCommandList(String text, Processor makeProcessor) {
213                this.startSymbols = text;
214                text = StringUtils.substring(text, 1);
215                commandListModel.removeAllElements();
216                exampleMap.clear();
217
218                List<CommandInfo> commandInfos = getCodeHelper().getCommandList(text, makeProcessor.getClass());
219                commandInfos.sort(Comparator.comparing(CommandInfo::getName));
220                List<CommandInfo> active = commandInfos.stream()
221                                .filter((a) -> !a.getClassName().equals(BaseProcessor.class.getSimpleName()))
222                                .collect(Collectors.toList());
223                List<CommandInfo> base = commandInfos.stream()
224                                .filter((a) -> a.getClassName().equals(BaseProcessor.class.getSimpleName()))
225                                .collect(Collectors.toList());
226
227                List<CommandInfo> sortedCommandInfos = new ArrayList<CommandInfo>(active);
228                sortedCommandInfos.addAll(base);
229
230                for (CommandInfo commandInfo : sortedCommandInfos) {
231                        String name = commandInfo.getName();
232                        commandListModel.addElement(name);
233                        exampleMap.put(name, commandInfo.getExamples());
234                }
235
236                if (commandListModel.isEmpty() || commandListModel.getSize() > 1
237                                || exampleMap.get(commandListModel.firstElement()).size() > 1) {
238                        showDialog();
239
240                        SwingUtilities.invokeLater(() -> {
241                                commands.requestFocusInWindow();
242                                commands.setSelectedIndex(0);
243                                fillExamples(commands.getSelectedValue());
244                        });
245                } else {
246                        String firstElement = commandListModel.firstElement();
247                        perform(firstElement);
248                }
249        }
250
251        public void helpWith(String text, boolean isCommand) {
252                if (isCommand && (StringUtils.startsWith(text, "<") || StringUtils.isBlank(text))) {
253                        Processor taskProcessor = getCurrentProcessor();
254                        fillCommandList(text, taskProcessor);
255                } else {
256                        DialogPopupMenu menu = new DialogPopupMenu(getCodeHelper().getEditor());
257                        menu.setAutoscrolls(true);
258                        if (!isCommand) {
259                                showMacroPopupMenu(text, menu);
260                        } else {
261                                menu = getCodeHelper().getEditor().getRecipePanel().contextHelp(menu);
262                        }
263                        Point magicCaretPosition = getCodeHelper().getEditor().getRecipePanel().getMagicCaretPosition();
264                        if (magicCaretPosition == null)
265                                magicCaretPosition = new Point();
266                        menu.show(getCodeHelper().getEditor(), magicCaretPosition.x, magicCaretPosition.y);
267                }
268        }
269
270        private Processor getCurrentProcessor() {
271                TaskEditor recipePanel = getCodeHelper().getRecipePanel();
272                TextEditor editor = recipePanel.getEditor();
273                String text = editor.getText();
274                int curpos = editor.getCaretPosition();
275
276                Processor makeProcessor = recipePanel.getProcessor();
277                String substring = StringUtils.substring(text, 0, curpos);
278                int startExternTag = StringUtils.lastIndexOf(substring, "<Extern");
279                int closeExternTag = StringUtils.lastIndexOf(substring, "</Extern");
280                if (closeExternTag < 0 || closeExternTag < startExternTag) {
281                        int endExternTag = StringUtils.indexOf(substring, '>', startExternTag);
282                        String externTag = StringUtils.substring(substring, startExternTag, endExternTag);
283                        if (StringUtils.isNotBlank(externTag)) {
284                                externTag = externTag + "/>";
285                                try {
286                                        Node externNode = new EasyParser().getObject(externTag);
287                                        makeProcessor = makeProcessor.makeProcessor(externNode);
288
289                                } catch (Exception e1) {
290                                        // do nothing.
291                                }
292                        }
293                }
294                return makeProcessor;
295        }
296
297        private void showMacroPopupMenu(final String theStartMacroIns, DialogPopupMenu menu) {
298
299                JMenuItem menuItem = new JMenuItem("$var{type:property,type:data}");
300                if ("var{".startsWith(theStartMacroIns)) {
301                        menu.add(menuItem);
302                        menuItem.addActionListener(new ActionListener() {
303                                public void actionPerformed(ActionEvent e) {
304                                        Node object;
305                                        try {
306                                                object = new EasyParser()
307                                                                .getObject("<Data variable_name='type:property' default_value='type:data'/>");
308                                                parsingCommandParamters(object);
309                                                String theStartMacroIns = getStartMacroIns();
310                                                String text = "var{" + object.getAttribute("variable_name") + ","
311                                                                + object.getAttribute("default_value") + "}";
312                                                insertText(theStartMacroIns, text);
313                                        } catch (Exception e1) {
314                                                e1.printStackTrace();
315                                        }
316                                }
317                        });
318                }
319
320                menuItem = new JMenuItem("$tag{type:property,type:data}");
321                if ("tag{".startsWith(theStartMacroIns)) {
322                        menu.add(menuItem);
323                        menuItem.addActionListener(new ActionListener() {
324
325                                public void actionPerformed(ActionEvent e) {
326                                        Node object;
327                                        try {
328                                                object = new EasyParser()
329                                                                .getObject("<Data variable_name='type:property' default_value='type:data'/>");
330                                                parsingCommandParamters(object);
331
332                                                String theStartMacroIns = getStartMacroIns();
333
334                                                insertText(theStartMacroIns, "tag{" + object.getAttribute("variable_name") + ","
335                                                                + object.getAttribute("default_value") + "}");
336                                        } catch (Exception e1) {
337                                                e1.printStackTrace();
338                                        }
339                                }
340                        });
341                }
342
343                if ("call{".startsWith(theStartMacroIns)) {
344                        menuItem = new JMenuItem("$call{type:recipe,type:data}");
345                        menu.add(menuItem);
346                        menuItem.addActionListener(new ActionListener() {
347                                public void actionPerformed(ActionEvent e) {
348                                        Node object;
349                                        try {
350                                                object = new EasyParser()
351                                                                .getObject("<Data task_name='type:recipe' return_variable='type:property'/>");
352                                                parsingCommandParamters(object);
353                                                String return_variable = object.getAttribute("return_variable");
354                                                insertText(getStartMacroIns(), "call{" + object.getAttribute("task_name")
355                                                                + (return_variable == null ? "" : "," + return_variable) + "}");
356                                        } catch (Exception e1) {
357                                                e1.printStackTrace();
358                                        }
359                                }
360                        });
361                }
362
363                if ("file{".startsWith(theStartMacroIns))
364
365                {
366                        menuItem = new JMenuItem("$file{type:path}");
367                        menu.add(menuItem);
368                        menuItem.addActionListener(e -> {
369                                Node object;
370                                try {
371                                        object = new EasyParser().getObject("<Data file_name='type:path'/>");
372                                        parsingCommandParamters(object);
373                                        insertText(getStartMacroIns(), "file{" + object.getAttribute("file_name") + "}");
374                                } catch (Exception e1) {
375                                        e1.printStackTrace();
376                                }
377                        });
378                }
379        }
380
381        private boolean parsingCommandParamters(Node node) {
382                boolean isHelpRequired = true;
383                Properties attributes = new Properties();
384                Node example = node;
385                if (example.isEmpty()) {
386                        example = new Node("example");
387                        example.add(node);
388                }
389                for (Node object : example) {
390                        for (Object name : object.getAttributes().keySet()) {
391                                String attribute = object.getAttribute((String) name);
392                                String theName = ((String) name).replace('_', ' ');
393                                if (attribute.startsWith("type:")) {
394                                        attribute = attribute.substring(5);
395                                        JRootPane rootPane = SwingUtilities.getRootPane(getCodeHelper().getEditor());
396                                        if (attribute.equals("integer")) {
397                                                boolean valid = true;
398                                                do {
399                                                        attribute = JOptionPane.showInputDialog(rootPane,
400                                                                        "Type: " + attribute + "\nAttribute: " + theName);
401                                                        if (attribute == null) {
402                                                                isHelpRequired = false;
403                                                                break;
404                                                        }
405
406                                                        object.setAttribute((String) name, attribute);
407
408                                                } while (!valid);
409
410                                        } else if (attribute.equals("operation")) {
411                                                Map<String, OperationHolder> operationsMethods = AEWorkspace.getInstance()
412                                                                .getOperationsMethods();
413                                                Set<String> keySet = operationsMethods.keySet();
414                                                showListDialog(object, name, attribute, keySet.toArray(new String[keySet.size()]), false,
415                                                                "Operations:");
416                                                String operationName = object.getAttribute("method");
417                                                if (!StringUtils.isEmpty(operationName)) {
418                                                        OperationHolder operationsMethod = AEWorkspace.getInstance()
419                                                                        .getOperationsMethod(operationName);
420                                                        object.setAttribute("description", operationsMethod.getDescription());
421                                                        Processor processor = getCodeHelper().getEditor().getRecipePanel().getProcessor();
422                                                        String[] array = processor.getVariables().keySet().toArray(new String[keySet.size()]);
423                                                        Class<?> returnType = operationsMethod.getMethod().getReturnType();
424                                                        if (returnType != void.class) {
425                                                                object.setAttribute("name", "type:property");
426
427                                                                if (!showListDialog(object, "name", "property", array, true, "Return: "
428                                                                                + operationsMethod.getReturnDescription() + "\nSelect variable name:")) {
429                                                                        isHelpRequired = false;
430                                                                        break;
431                                                                }
432                                                        }
433
434                                                        Class<?>[] parameterTypes = operationsMethod.getMethod().getParameterTypes();
435                                                        for (int i = 0; i < parameterTypes.length; i++) {
436                                                                String type = parameterTypes[i].getName();
437
438                                                                object.setAttribute("arg" + (i + 1), type);
439                                                                String value = (String) JOptionPane.showInputDialog(rootPane,
440                                                                                "Type: " + type + "\nAttribute: " + operationsMethod.getParameterName(i),
441                                                                                "Input parameter", JOptionPane.INFORMATION_MESSAGE, null, null, null);
442                                                                if (attribute == null) {
443                                                                        isHelpRequired = false;
444                                                                        break;
445                                                                }
446
447                                                                object.setAttribute("arg" + (i + 1), value);
448                                                        }
449                                                }
450                                                isHelpRequired = false;
451                                                break;
452                                        } else if (attribute.equals("attr")) {
453                                                attribute = attributes.getProperty(theName);
454                                                object.setAttribute((String) name, attribute);
455                                        } else if (StringUtils.containsAny(attribute, "string", "url", "regex")) {
456                                                String value = OptionPane.showInputDialog(rootPane, "Input command attribute", "Attribute: " + theName + ", Type: " + attribute, "");
457                                                if (value == null) {
458                                                        isHelpRequired = false;
459                                                        break;
460                                                }
461                                                
462                                                value = StringEscapeUtils.escapeXml(value);
463                                                object.setAttribute((String) name, value);
464                                        } else if (attribute.equals("xpath")) {
465                                                attribute = JOptionPane.showInputDialog(rootPane, "Attribute: " + theName + "\nType: xpath",
466                                                                "");
467                                                if (attribute != null) {
468                                                        attribute = attribute.replace("\"", "\'");
469                                                }
470                                                if (attribute == null) {
471                                                        isHelpRequired = false;
472                                                        break;
473                                                }
474                                                object.setAttribute((String) name, attribute);
475                                        } else if (attribute.equals("time")) {
476                                                String[] choiceArray = new String[] { "", "s", "m", "h", "d", "M", "Y" };
477                                                if (!showListDialog(object, name, "time", choiceArray, false, null)) {
478                                                        isHelpRequired = false;
479                                                        break;
480                                                }
481                                        } else if (attribute.equals("recipe")) {
482                                                if (!showListDialog(object, name, attribute,
483                                                                getCodeHelper().getEditor().getRecipePanel().getManager().getTestsList(), true)) {
484                                                        isHelpRequired = false;
485                                                        break;
486                                                }
487                                        } else if (attribute.equals("double")) {
488                                                attribute = JOptionPane.showInputDialog(rootPane, "Attribute: " + theName + "\nType: double",
489                                                                "");
490                                                if (attribute == null) {
491                                                        isHelpRequired = false;
492                                                        break;
493                                                }
494                                                object.setAttribute((String) name, attribute);
495                                        } else if (attribute.equals("property")) {
496                                                Processor processor = getCodeHelper().getEditor().getRecipePanel().getProcessor();
497                                                if (processor == null) {
498                                                        TaskEditor recipePanel = getCodeHelper().getEditor().getRecipePanel();
499                                                        processor = new BaseProcessor(recipePanel.getManager(), recipePanel.getLogger(),
500                                                                        getCodeHelper().getEditor().getRecipePanel().getManager().getStartDir());
501                                                }
502                                                Set<String> keySet = processor.getVariables().keySet();
503                                                if (!showListDialog(object, name, attribute, keySet.toArray(new String[keySet.size()]), true)) {
504                                                        isHelpRequired = false;
505                                                        break;
506                                                }
507                                        } else if (attribute.equals("path")) {
508                                                FileDialog theFileDialog = new FileDialog(JOptionPane.getRootFrame(), "Input path",
509                                                                FileDialog.LOAD);
510                                                String absolutePath = getCodeHelper().getEditor().getRecipePanel().getProcessor()
511                                                                .getBaseDir().getAbsolutePath();
512                                                theFileDialog.setDirectory(absolutePath);
513                                                theFileDialog.setVisible(true);
514                                                if (theFileDialog.getFile() != null) {
515                                                        String prefDir = theFileDialog.getDirectory();
516                                                        if (theFileDialog.getDirectory().startsWith(absolutePath)) {
517                                                                prefDir = prefDir.substring(absolutePath.length() + 1, prefDir.length());
518                                                        }
519                                                        object.setAttribute((String) name, prefDir + theFileDialog.getFile());
520                                                }
521                                        } else if (attribute.startsWith("boolean")) {
522                                                String type = "boolean";
523                                                String[] choiceArray = new String[] { "true", "false" };
524                                                if (!showListDialog(object, name, type, choiceArray, false)) {
525                                                        isHelpRequired = false;
526                                                        break;
527                                                }
528                                        } else if (attribute.startsWith("processor")) {
529                                                String[] processors = ClassUtils.findAssignable(Processor.class, Processor.class.getPackage());
530
531                                                if (!showListDialog(object, name, attribute, processors, false)) {
532                                                        isHelpRequired = false;
533                                                        break;
534                                                }
535                                        } else if (attribute.startsWith("view")) {
536                                                String[] processors = ClassUtils.findAssignable(View.class, View.class.getPackage());
537
538                                                if (!showListDialog(object, name, attribute, processors, false)) {
539                                                        isHelpRequired = false;
540                                                        break;
541                                                }
542                                        }
543
544                                } else if (attribute.startsWith("enum:")) {
545                                        String type = attribute.substring(0, 4);
546                                        String choice = attribute.substring(5);
547                                        StringTokenizer stringTokenizer = new StringTokenizer(choice, "|");
548                                        String[] choiceArray = new String[stringTokenizer.countTokens()];
549                                        for (int i = 0; i < choiceArray.length; i++) {
550                                                choiceArray[i] = stringTokenizer.nextToken();
551                                        }
552                                        if (!showListDialog(object, name, type, choiceArray, false)) {
553                                                isHelpRequired = false;
554                                                break;
555                                        }
556                                }
557                        }
558                        attributes.putAll(object.getAttributes());
559                }
560                return isHelpRequired;
561        }
562
563        private boolean showListDialog(Node object, Object name, String type, String[] sourceList, boolean b) {
564                Arrays.sort(sourceList);
565                return showListDialog(object, name, type, sourceList, b, null);
566        }
567
568        private boolean showListDialog(Node object, Object name, String type, String[] sourceList, boolean b,
569                        String description) {
570
571                String prefix = "Attribute: ";
572
573                String message = StringUtils.defaultString(description, prefix + name + ", Type: " + type);
574                JRootPane rootPane = SwingUtilities.getRootPane(getCodeHelper().getEditor().getRecipePanel().getEditor());
575                String value = OptionPane.showInputDialog(rootPane, message, "Input command attribute", sourceList, "");
576
577                if (value == null) {
578                        return false;
579                }
580
581                object.setAttribute((String) name, value);
582                return true;
583        }
584
585        void insertTag(final String startSymbols, String text) {
586                try {
587                        Node object = new EasyParser().getObject("<example>" + text + "</example>");
588                        parsingCommandParamters(object);
589                        StringBuilder code = new StringBuilder();
590                        for (Node node : object) {
591                                code.append(node.getXMLText());
592                        }
593                        insertText(startSymbols, code.toString().trim());
594                } catch (TaskCancelingException e) {
595                } catch (Exception e) {
596                        JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), e.getMessage());
597                }
598        }
599
600        private String getStartMacroIns() {
601                int curpos = getCodeHelper().getEditor().getCaretPosition();
602                String text = getCodeHelper().getEditor().getText();
603                String theStartMacroIns = null;
604
605                int i;
606                for (i = curpos - 1; i >= 0; i--) {
607                        char charAt = text.charAt(i);
608
609                        if (charAt == '$') {
610                                theStartMacroIns = text.substring(i + 1, curpos);
611                                break;
612                        }
613                }
614
615                return (i > curpos - 7) ? theStartMacroIns : "";
616        }
617
618        private void insertText(String theStartCommand, String text) {
619                int caretPosition2 = getCodeHelper().getEditor().getCaretPosition();
620                int i = caretPosition2 - theStartCommand.length();
621                try {
622                        String text2 = getCodeHelper().getEditor().getRecipePanel().getEditor().getText(i - 1, 1);
623                        if ("<".equals(text2)) {
624                                i--;
625                        }
626                } catch (BadLocationException e) {
627                        e.printStackTrace();
628                }
629                getCodeHelper().getEditor().replaceRange(text, i, caretPosition2);
630        }
631
632}