Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: b21aaab512da20fb6dce0ff2e81f7810264bd85f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/*******************************************************************************
 * Copyright (c) 2008 Phil Muldoon <pkmuldoon@picobot.org>.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Phil Muldoon <pkmuldoon@picobot.org> - initial API and implementation.
 *******************************************************************************/

package org.eclipse.linuxtools.internal.systemtap.ui.ide.editors.stp;

import java.util.ArrayList;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.reconciler.DirtyRegion;
import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
import org.eclipse.swt.widgets.Display;

/**
 *
 * Reconciling strategy for Systemtap editor code folding positions. The positional aspects
 * of document tag discovery should really be placed with a position builder
 *
 */
public class STPReconcilingStrategy  implements IReconcilingStrategy,
               IReconcilingStrategyExtension {

    // Constants
    protected static final int STP_NO_TAG = 0;
    protected static final int STP_MULTILINE_COMMENT_TAG = 1;
    protected static final int STP_PROBE = 2;
    protected static final int STP_FUNCTION = 3;

    // Next Character Position
    protected int nextCharPosition = 0;

    // Current tag start
    protected int currentTagStart = 0;

    // Current tag end
    protected int currentTagEnd = 0;

    // List of positions
    protected final ArrayList<Position> documentPositionList = new ArrayList<>();

    // The end offset of the range to be scanned *//*
    protected int endOfDocumentPostion;

    private IDocument currentDocument;
    private STPEditor currentEditor;

    /**
     * Sets the current editor.
     */
    public void setEditor(STPEditor editor) {
        this.currentEditor = editor;
    }

    /**
     * Sets the current (ie working) document.
     */
    @Override
    public void setDocument(IDocument document) {
        this.currentDocument = document;
    }

    @Override
    public void reconcile(IRegion partition) {
        // Just rebuild the whole document
        initialReconcile();
    }

    @Override
    public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
        //Just rebuild the whole document
        initialReconcile();
    }

    @Override
    public void initialReconcile() {
        endOfDocumentPostion = currentDocument.getLength();
        try {
            calculatePositions();
        } catch (BadLocationException e) {
            // Cannot reconcile, return
            return;
        }
    }

    @Override
    public void setProgressMonitor(IProgressMonitor monitor) {

    }

    /**
     *
     * From currentDocument, calculate beginning of document
     * to endOfDocumentPostion to build positions for code folding.
     *
     * @throws BadLocationException
     */
    private void calculatePositions() throws BadLocationException {
        // Clear old positions and reset to beginning of document
        documentPositionList.clear();
        nextCharPosition = 0;

        // Build the actual document positions
        buildPositions();

        // Paint the folding annotations in the background.
        Display.getDefault().asyncExec(() -> currentEditor.updateFoldingStructure(documentPositionList));
    }

    /**
     *
     * Start trying to guess if given char z, what - if any - tag this
     * begins.
     *
     * @param location - location of current position
     * @return - tag type, if any
     *
     * @throws BadLocationException
     */
    private int classifyComponent(int location) throws BadLocationException {
        int deltaLocation = location;
        char ch = currentDocument.getChar(deltaLocation);
        switch (ch) {
            // The 'comment' case.
            case '/':
                deltaLocation++;
                ch = currentDocument.getChar(deltaLocation);
                if (ch == '*') {
                    currentTagStart = location;
                    deltaLocation++;
                    nextCharPosition = deltaLocation;
                    return STP_MULTILINE_COMMENT_TAG;
                }
                break;
            // The 'probe' case.
            case 'p':
                if (isProbe()) {
                    currentTagStart = location;
                    return STP_PROBE;
                }

            // The 'function' case.
            case 'f':
                if (isFunction()) {
                    currentTagStart = location;
                    return STP_FUNCTION;
                }
            // No tag, don't fold region.
            default:
                break;
        }
        return STP_NO_TAG;
    }

    /**
     *
     * Build a list of locations to mark beginning and end of folding regions.
     *
     * @throws BadLocationException
     */
    private void buildPositions() throws BadLocationException {
        while (nextCharPosition < endOfDocumentPostion) {
            switch (classifyComponent(nextCharPosition))
            {
                // All of these cases have found the beginning of a tag
                // to start folding. Each element must now be find
                // the end of the region it represents.
                case STP_MULTILINE_COMMENT_TAG:
                    currentTagEnd = findEndOfComment();
                    writePosition(currentTagStart,currentTagEnd);
                    nextCharPosition = currentTagStart + currentTagEnd;
                    break;
                case STP_PROBE:
                case STP_FUNCTION:
                    currentTagEnd = findEndOfProbeOrFunction();
                    writePosition(currentTagStart,currentTagEnd);
                    nextCharPosition = currentTagStart + currentTagEnd;
                    break;
                default:
                    nextCharPosition++;
                    break;
            }
        }
    }

    /**
     *
     * Write a Position to the position list.
     *
     * @param startOffset - start of position in the document.
     * @param length - length of position.
     *
     */
    private void writePosition(int startOffset, int length) {
        if (length > 0)
            documentPositionList.add(new Position(startOffset, length));
    }

    private boolean isProbe() throws BadLocationException {
        return matchKeyWord("probe"); //$NON-NLS-1$
    }

    private boolean isFunction() throws BadLocationException {
        return matchKeyWord("function"); //$NON-NLS-1$
    }

    private boolean matchKeyWord(String word) throws BadLocationException {
        StringBuffer keyWord = new StringBuffer();
        int location = nextCharPosition;
        while (location < endOfDocumentPostion) {
            char ch = currentDocument.getChar(location);
            if ((ch == ' ') || (!Character.isLetter(ch)))
                break;
            else
                keyWord.append(ch);
            location++;
        }
        if (keyWord.toString().compareTo(word) == 0)
            return true;
        return false;
    }

    private int findEndOfProbeOrFunction() throws BadLocationException {
        int bracketCount = 0;
        boolean firstBracket = false;
        char ch;

        while (nextCharPosition < endOfDocumentPostion) {
            ch = currentDocument.getChar(nextCharPosition);
            if (ch == '{') {
                firstBracket = true;
                bracketCount++;
            }
            if (ch == '}')
                bracketCount--;
            if ((bracketCount == 0) && (firstBracket))
                return (nextCharPosition-currentTagStart)+2;
            nextCharPosition++;
        }
        return -1;
    }

    private int findEndOfComment() throws BadLocationException {
        while (nextCharPosition < endOfDocumentPostion) {
            char ch = currentDocument.getChar(nextCharPosition);
            if (ch == '*') {
                nextCharPosition++;
                ch = currentDocument.getChar(nextCharPosition);
                if (ch == '/')
                    return (nextCharPosition-currentTagStart)+2;
            }
            nextCharPosition++;
        }
        return -1;
    }
}

Back to the top