PLSQL/Lexer/src/org/netbeans/modules/plsql/lexer/PlsqlBlockFactory.java
author Subhashini Sooriarachchi <subslk@netbeans.org>
Mon, 12 Aug 2013 11:26:54 +0530
changeset 464 e10b2e8563fc
parent 405 f949ce7a3fb1
permissions -rw-r--r--
EADS-3749 encountering issues with the displaying of code in Developer Studio when code folding is enabled
jrechtacek@0
     1
/*
jrechtacek@0
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jrechtacek@0
     3
 *
jrechtacek@0
     4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
jrechtacek@0
     5
 *
jrechtacek@0
     6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
jrechtacek@0
     7
 * Other names may be trademarks of their respective owners.
jrechtacek@0
     8
 *
jrechtacek@0
     9
 * The contents of this file are subject to the terms of either the GNU
jrechtacek@0
    10
 * General Public License Version 2 only ("GPL") or the Common
jrechtacek@0
    11
 * Development and Distribution License("CDDL") (collectively, the
jrechtacek@0
    12
 * "License"). You may not use this file except in compliance with the
jrechtacek@0
    13
 * License. You can obtain a copy of the License at
jrechtacek@0
    14
 * http://www.netbeans.org/cddl-gplv2.html
jrechtacek@0
    15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jrechtacek@0
    16
 * specific language governing permissions and limitations under the
jrechtacek@0
    17
 * License.  When distributing the software, include this License Header
jrechtacek@0
    18
 * Notice in each file and include the License file at
jrechtacek@0
    19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
jrechtacek@0
    20
 * particular file as subject to the "Classpath" exception as provided
jrechtacek@0
    21
 * by Oracle in the GPL Version 2 section of the License file that
jrechtacek@0
    22
 * accompanied this code. If applicable, add the following below the
jrechtacek@0
    23
 * License Header, with the fields enclosed by brackets [] replaced by
jrechtacek@0
    24
 * your own identifying information:
jrechtacek@0
    25
 * "Portions Copyrighted [year] [name of copyright owner]"
jrechtacek@0
    26
 *
jrechtacek@0
    27
 * If you wish your version of this file to be governed by only the CDDL
jrechtacek@0
    28
 * or only the GPL Version 2, indicate your decision by adding
jrechtacek@0
    29
 * "[Contributor] elects to include this software in this distribution
jrechtacek@0
    30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
jrechtacek@0
    31
 * single choice of license, a recipient has the option to distribute
jrechtacek@0
    32
 * your version of this file under either the CDDL, the GPL Version 2 or
jrechtacek@0
    33
 * to extend the choice of license to its licensees as provided above.
jrechtacek@0
    34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
jrechtacek@0
    35
 * Version 2 license, then the option applies only if the new code is
jrechtacek@0
    36
 * made subject to such option by the copyright holder.
jrechtacek@0
    37
 *
jrechtacek@0
    38
 * Contributor(s):
jrechtacek@0
    39
 *
jrechtacek@0
    40
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
jrechtacek@0
    41
 */
jrechtacek@0
    42
package org.netbeans.modules.plsql.lexer;
jrechtacek@0
    43
jrechtacek@0
    44
import java.util.ArrayList;
jrechtacek@0
    45
import java.util.Collections;
jrechtacek@0
    46
import java.util.HashMap;
jrechtacek@0
    47
import java.util.HashSet;
jrechtacek@0
    48
import java.util.LinkedList;
jrechtacek@0
    49
import java.util.List;
jrechtacek@0
    50
import java.util.Locale;
jrechtacek@0
    51
import java.util.Map;
jrechtacek@0
    52
import java.util.Observable;
jrechtacek@0
    53
import java.util.StringTokenizer;
chrislovsund@362
    54
import java.util.logging.Level;
chrislovsund@362
    55
import java.util.logging.Logger;
jrechtacek@0
    56
import javax.swing.SwingUtilities;
jrechtacek@0
    57
import javax.swing.event.DocumentEvent;
jrechtacek@0
    58
import javax.swing.event.DocumentListener;
jrechtacek@0
    59
import javax.swing.text.AbstractDocument;
jrechtacek@0
    60
import javax.swing.text.BadLocationException;
jrechtacek@0
    61
import javax.swing.text.Document;
jrechtacek@0
    62
import org.netbeans.api.lexer.Token;
jrechtacek@0
    63
import org.netbeans.api.lexer.TokenHierarchy;
jrechtacek@0
    64
import org.netbeans.api.lexer.TokenSequence;
jrechtacek@0
    65
import org.openide.ErrorManager;
jrechtacek@0
    66
import org.openide.util.RequestProcessor;
jrechtacek@0
    67
jrechtacek@0
    68
/**
jrechtacek@0
    69
 * Class that will maintain code blocks of the file.
chrislovsund@362
    70
 *
jrechtacek@0
    71
 * @author YaDhLK
jrechtacek@0
    72
 */
jrechtacek@0
    73
public class PlsqlBlockFactory extends Observable implements DocumentListener {
jrechtacek@0
    74
chrislovsund@362
    75
    private static final Logger LOG = Logger.getLogger(PlsqlBlockFactory.class.getName());
chrislovsund@177
    76
    private List<PlsqlBlock> blockHierarchy;
chrislovsund@177
    77
    private List<PlsqlBlock> customFoldBlocks;
chrislovsund@177
    78
    private List<PlsqlBlock> newBlocks;
chrislovsund@177
    79
    private List<PlsqlBlock> toBeRemoved;
chrislovsund@177
    80
    private List<PlsqlBlock> changedBlocks;
chrislovsund@177
    81
    private HashSet<Integer> unsuccessBlocks;
chrislovsund@177
    82
    private HashMap<String, String> definesMap;
chrislovsund@177
    83
    private TokenHierarchy tokenHierarchy;
chrislovsund@177
    84
    private int docStartOffset = 0;
chrislovsund@177
    85
    private int docEndOffset = 0;
chrislovsund@177
    86
    private int startParse = 0;
chrislovsund@177
    87
    private int endParse = 0;
chrislovsund@177
    88
    private int changedLength = 0;
chrislovsund@177
    89
    private boolean isDefineChanged = false;
chrislovsund@177
    90
    private static RequestProcessor.Task updateBlocksTask = null;
chrislovsund@177
    91
    private static final LinkedList<EventProperties> updateEvents = new LinkedList<EventProperties>();
chrislovsund@177
    92
    private static final int DEFAULT_WAIT_TIME = 500;
chrislovsund@177
    93
    private boolean saveInProgress = false;
chrislovsund@177
    94
    private boolean caseChangeInProgress = false;
chrislovsund@177
    95
    private static final String updateLock = "This is used to synchronize navigator updates";
chrislovsund@177
    96
    private static final RequestProcessor RP = new RequestProcessor(PlsqlBlockFactory.class);
chrislovsund@177
    97
chrislovsund@177
    98
    public PlsqlBlockFactory() {
chrislovsund@177
    99
        blockHierarchy = new ArrayList<PlsqlBlock>();
chrislovsund@177
   100
        tokenHierarchy = null;
chrislovsund@177
   101
        newBlocks = new ArrayList<PlsqlBlock>();
chrislovsund@177
   102
        toBeRemoved = new ArrayList<PlsqlBlock>();
chrislovsund@177
   103
        changedBlocks = new ArrayList<PlsqlBlock>();
chrislovsund@177
   104
        customFoldBlocks = new ArrayList<PlsqlBlock>();
chrislovsund@177
   105
        definesMap = new HashMap<String, String>();
chrislovsund@177
   106
        unsuccessBlocks = new HashSet<Integer>();
chrislovsund@177
   107
    }
chrislovsund@177
   108
chrislovsund@177
   109
    /**
chrislovsund@177
   110
     * Method used to reparse the whole document
chrislovsund@362
   111
     *
chrislovsund@177
   112
     * @param doc
chrislovsund@177
   113
     */
chrislovsund@177
   114
    public void reParse(Document doc) {
chrislovsund@177
   115
        clear();
chrislovsund@177
   116
chrislovsund@177
   117
        if (doc == null) {
chrislovsund@177
   118
            return;
chrislovsund@177
   119
        }
chrislovsund@177
   120
chrislovsund@177
   121
        docStartOffset = doc.getStartPosition().getOffset();
chrislovsund@177
   122
        docEndOffset = doc.getEndPosition().getOffset();
chrislovsund@177
   123
        startParse = docStartOffset;
chrislovsund@177
   124
        endParse = docEndOffset - 1;
chrislovsund@177
   125
chrislovsund@177
   126
        //clean block hierarchy
chrislovsund@177
   127
        blockHierarchy.clear();
chrislovsund@177
   128
        customFoldBlocks.clear();
chrislovsund@177
   129
        generateBlocks(doc);
chrislovsund@177
   130
    }
chrislovsund@177
   131
chrislovsund@177
   132
    /**
chrislovsund@177
   133
     * Return new blocks that were recognized by the latest change
chrislovsund@362
   134
     *
chrislovsund@177
   135
     * @return
chrislovsund@177
   136
     */
chrislovsund@177
   137
    public List<PlsqlBlock> getNewBlocks() {
chrislovsund@177
   138
        return newBlocks;
chrislovsund@177
   139
    }
chrislovsund@177
   140
chrislovsund@177
   141
    /**
chrislovsund@177
   142
     * Return the blocks who's offsets have changed
chrislovsund@362
   143
     *
chrislovsund@177
   144
     * @return
chrislovsund@177
   145
     */
chrislovsund@177
   146
    public List<PlsqlBlock> getChangedBlocks() {
chrislovsund@177
   147
        return changedBlocks;
chrislovsund@177
   148
    }
chrislovsund@177
   149
chrislovsund@177
   150
    /**
chrislovsund@177
   151
     * Return the custom fold blocks that are there
chrislovsund@362
   152
     *
chrislovsund@177
   153
     * @return
chrislovsund@177
   154
     */
chrislovsund@177
   155
    public List<PlsqlBlock> getCustomFolds() {
chrislovsund@177
   156
        return customFoldBlocks;
chrislovsund@177
   157
    }
chrislovsund@177
   158
chrislovsund@177
   159
    /**
chrislovsund@177
   160
     * Return block hierarchy
chrislovsund@362
   161
     *
chrislovsund@177
   162
     * @return
chrislovsund@177
   163
     */
chrislovsund@177
   164
    public List<PlsqlBlock> getBlockHierarchy() {
chrislovsund@177
   165
        return blockHierarchy;
chrislovsund@177
   166
    }
chrislovsund@177
   167
chrislovsund@177
   168
    /**
chrislovsund@177
   169
     * Method that will return the blocks that are removed
chrislovsund@362
   170
     *
chrislovsund@177
   171
     * @return
chrislovsund@177
   172
     */
chrislovsund@177
   173
    public List<PlsqlBlock> getRemovedBlocks() {
chrislovsund@177
   174
        return toBeRemoved;
chrislovsund@177
   175
    }
chrislovsund@177
   176
chrislovsund@177
   177
    /**
chrislovsund@177
   178
     * Check whether there are childrean of this fold here, if so add them
chrislovsund@362
   179
     *
chrislovsund@177
   180
     * @param block
chrislovsund@177
   181
     * @param immediateBlockHier
chrislovsund@177
   182
     */
chrislovsund@177
   183
    private void addImmediateChildren(PlsqlBlock block, List<PlsqlBlock> immediateBlockHier) {
chrislovsund@177
   184
        for (int i = immediateBlockHier.size() - 1; i >= 0; i--) {
chrislovsund@177
   185
            PlsqlBlock tmp = immediateBlockHier.get(i);
chrislovsund@177
   186
            if ((tmp.getStartOffset() > block.getStartOffset())
chrislovsund@177
   187
                    && (tmp.getEndOffset() < block.getEndOffset())) {
chrislovsund@177
   188
                if (checkExisting(tmp, newBlocks)) {
chrislovsund@177
   189
                    newBlocks.remove(tmp);
chrislovsund@177
   190
                } else {
chrislovsund@177
   191
                    removeBlock(block, immediateBlockHier);
chrislovsund@177
   192
                }
chrislovsund@177
   193
chrislovsund@177
   194
                block.addChild(tmp);
chrislovsund@177
   195
            }
chrislovsund@177
   196
        }
chrislovsund@177
   197
    }
chrislovsund@177
   198
chrislovsund@177
   199
    /**
chrislovsund@177
   200
     * Method that will look for custom start or end token based on the given type
chrislovsund@362
   201
     *
chrislovsund@177
   202
     * @param customEndToken
chrislovsund@177
   203
     * @param ts
chrislovsund@177
   204
     * @param immediateBlockHier
chrislovsund@177
   205
     * @param parent
chrislovsund@177
   206
     * @param type
chrislovsund@177
   207
     */
chrislovsund@177
   208
    private void checkCustom(Token<PlsqlTokenId> customToken, TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> immediateBlockHier, PlsqlBlock parent, String type) {
chrislovsund@177
   209
        Token<PlsqlTokenId> found = customToken;
chrislovsund@177
   210
        Token<PlsqlTokenId> token = customToken;
chrislovsund@177
   211
chrislovsund@177
   212
        if (type.equals("START")) {
chrislovsund@177
   213
            //We have to find the end fold token now
chrislovsund@177
   214
            ts.move(found.offset(tokenHierarchy));
chrislovsund@177
   215
            ts.moveNext();
chrislovsund@177
   216
            while (ts.moveNext()) {
chrislovsund@177
   217
                token = ts.token();
chrislovsund@177
   218
                String image = token.text().toString();
chrislovsund@177
   219
                PlsqlTokenId tokenID = token.id();
chrislovsund@177
   220
chrislovsund@177
   221
                if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
   222
                    //only single comment line
chrislovsund@177
   223
                    if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
   224
                        //We have come to another start
chrislovsund@177
   225
                        return;
chrislovsund@177
   226
                    } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
   227
                        if (isTokenOk(token, immediateBlockHier, parent)) {
chrislovsund@177
   228
                            String name = found.text().toString();
chrislovsund@177
   229
                            int index = name.toUpperCase(Locale.ENGLISH).indexOf("<FOLD>");
chrislovsund@177
   230
                            name = name.substring(index + 7).trim();
chrislovsund@177
   231
                            if (ts.moveNext()) {
chrislovsund@177
   232
                                token = ts.token();
chrislovsund@177
   233
                                PlsqlBlock custom = new PlsqlBlock(found.offset(tokenHierarchy),
chrislovsund@177
   234
                                        token.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
   235
                                customFoldBlocks.add(custom);
chrislovsund@177
   236
                            }
chrislovsund@177
   237
                        }
chrislovsund@177
   238
                        //since we have found the other tag return
chrislovsund@177
   239
                        return;
chrislovsund@177
   240
                    }
chrislovsund@177
   241
                }
chrislovsund@177
   242
            }
chrislovsund@177
   243
        } else {
chrislovsund@177
   244
            ts.move(found.offset(tokenHierarchy));
chrislovsund@177
   245
            //We have to find the start fold token now
chrislovsund@177
   246
            while (ts.movePrevious()) {
chrislovsund@177
   247
                token = ts.token();
chrislovsund@177
   248
                String image = token.text().toString();
chrislovsund@177
   249
                PlsqlTokenId tokenID = token.id();
chrislovsund@177
   250
chrislovsund@177
   251
                if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
   252
                    //only single comment line
chrislovsund@177
   253
                    if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
   254
                        if (isTokenOk(token, immediateBlockHier, parent)) {
chrislovsund@177
   255
                            String name = image;
chrislovsund@177
   256
                            int index = name.toUpperCase(Locale.ENGLISH).indexOf("<FOLD>");
chrislovsund@177
   257
                            name = name.substring(index + 7).trim();
chrislovsund@177
   258
                            ts.move(found.offset(tokenHierarchy));
chrislovsund@177
   259
                            ts.moveNext();
chrislovsund@177
   260
                            if (ts.moveNext()) {
chrislovsund@177
   261
                                found = ts.token();
chrislovsund@177
   262
                                PlsqlBlock custom = new PlsqlBlock(token.offset(tokenHierarchy),
chrislovsund@177
   263
                                        found.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
   264
                                customFoldBlocks.add(custom);
chrislovsund@177
   265
                            }
chrislovsund@177
   266
                        }
chrislovsund@177
   267
                        //since we have found the other tag return
chrislovsund@177
   268
                        return;
chrislovsund@177
   269
                    } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
   270
                        //We have come to another end
chrislovsund@177
   271
                        return;
chrislovsund@177
   272
                    }
chrislovsund@177
   273
                }
chrislovsund@177
   274
            }
chrislovsund@177
   275
        }
chrislovsund@177
   276
    }
chrislovsund@177
   277
chrislovsund@177
   278
    /**
chrislovsund@177
   279
     * Method that will check for a Java Source block
chrislovsund@362
   280
     *
chrislovsund@177
   281
     * @param tempToken
chrislovsund@177
   282
     * @param ts
chrislovsund@177
   283
     * @param immediateBlockHier
chrislovsund@177
   284
     * @return
chrislovsund@177
   285
     */
chrislovsund@177
   286
    private PlsqlBlock checkJavaSource(Token<PlsqlTokenId> tempToken, TokenSequence<PlsqlTokenId> ts) {
chrislovsund@177
   287
        Token<PlsqlTokenId> begin = tempToken;
chrislovsund@177
   288
        Token<PlsqlTokenId> tmp = tempToken;
chrislovsund@177
   289
        PlsqlBlock block = null;
chrislovsund@177
   290
chrislovsund@177
   291
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
   292
        if (sqlPlusLine(ts)) {
chrislovsund@177
   293
            return null;
chrislovsund@177
   294
        }
chrislovsund@177
   295
chrislovsund@177
   296
        while (ts.moveNext()) {
chrislovsund@177
   297
            tmp = ts.token();
chrislovsund@177
   298
            String image = tmp.text().toString();
chrislovsund@177
   299
            PlsqlTokenId tokenID = tmp.id();
chrislovsund@177
   300
chrislovsund@362
   301
            if ((!image.equals("/")) && (tmp.offset(tokenHierarchy) > endParse)) {
chrislovsund@177
   302
                break;
chrislovsund@177
   303
            }
chrislovsund@177
   304
chrislovsund@177
   305
            //We might have come to the end of the procedure/function declaration
chrislovsund@177
   306
            if ((tokenID == PlsqlTokenId.OPERATOR) && image.equals("/")) {
chrislovsund@177
   307
                //check whether previous Non white space token to the identifier is END
chrislovsund@177
   308
                int offset = ts.offset();
chrislovsund@177
   309
                if (checkForOnlyChar(ts, offset)) {
chrislovsund@177
   310
                    ts.move(offset);
chrislovsund@177
   311
                    ts.moveNext();
chrislovsund@177
   312
                    ts.moveNext();
chrislovsund@177
   313
                    block = new PlsqlBlock(begin.offset(tokenHierarchy), offset, "", "", PlsqlBlockType.JAVA_SOURCE);
chrislovsund@177
   314
                    checkPrefix(begin.offset(tokenHierarchy), ts, block);
chrislovsund@177
   315
                    break;
chrislovsund@177
   316
                }
chrislovsund@177
   317
            }
chrislovsund@177
   318
        }
chrislovsund@177
   319
chrislovsund@177
   320
        return block;
chrislovsund@177
   321
    }
chrislovsund@177
   322
chrislovsund@177
   323
    /**
chrislovsund@177
   324
     * Check whether this current token is the only token in this line
chrislovsund@362
   325
     *
chrislovsund@177
   326
     * @param ts
chrislovsund@177
   327
     * @param offset
chrislovsund@177
   328
     * @return
chrislovsund@177
   329
     */
chrislovsund@177
   330
    private boolean checkForOnlyChar(TokenSequence<PlsqlTokenId> ts, int offset) {
chrislovsund@177
   331
        boolean isStartOk = true;
chrislovsund@177
   332
        boolean isEndOk = true;
chrislovsund@177
   333
        ts.move(offset);
chrislovsund@177
   334
        Token<PlsqlTokenId> token = null;
chrislovsund@177
   335
        while (ts.movePrevious()) {
chrislovsund@177
   336
            token = ts.token();
chrislovsund@177
   337
            if (token.id() == PlsqlTokenId.WHITESPACE) {
chrislovsund@177
   338
                if (token.toString().contains("\n")) {
chrislovsund@177
   339
                    break;
chrislovsund@177
   340
                }
chrislovsund@177
   341
            } else if (token.id() == PlsqlTokenId.JAVA_SOUCE) {
chrislovsund@177
   342
                break;
jrechtacek@0
   343
            } else {
chrislovsund@177
   344
                isStartOk = false;
chrislovsund@177
   345
                break;
jrechtacek@0
   346
            }
chrislovsund@177
   347
        }
chrislovsund@177
   348
chrislovsund@177
   349
        ts.move(offset);
chrislovsund@177
   350
        ts.moveNext(); //current token
chrislovsund@177
   351
        while (ts.moveNext()) {
chrislovsund@177
   352
            token = ts.token();
chrislovsund@177
   353
            if (token.id() == PlsqlTokenId.WHITESPACE) {
chrislovsund@177
   354
                if (token.toString().contains("\n")) {
chrislovsund@177
   355
                    break;
chrislovsund@177
   356
                }
chrislovsund@177
   357
            } else {
chrislovsund@177
   358
                isEndOk = false;
chrislovsund@177
   359
                break;
chrislovsund@177
   360
            }
chrislovsund@177
   361
        }
chrislovsund@177
   362
chrislovsund@177
   363
        ts.move(offset);
chrislovsund@177
   364
        ts.moveNext();
chrislovsund@177
   365
chrislovsund@177
   366
        if (isStartOk && isEndOk) {
chrislovsund@177
   367
            return true;
chrislovsund@177
   368
        }
chrislovsund@177
   369
chrislovsund@177
   370
        return false;
chrislovsund@177
   371
    }
chrislovsund@177
   372
chrislovsund@177
   373
    /**
chrislovsund@177
   374
     * Method that will check for statement blocks other than the CURSOR and VIEW
chrislovsund@362
   375
     *
chrislovsund@177
   376
     * @param tempToken
chrislovsund@177
   377
     * @param ts
chrislovsund@177
   378
     * @param immediateBlockHier
chrislovsund@177
   379
     * @return
chrislovsund@177
   380
     */
chrislovsund@177
   381
    private PlsqlBlock checkStatementBlock(Token<PlsqlTokenId> current, TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
   382
        List<PlsqlBlock> lstChild = new ArrayList<PlsqlBlock>();
chrislovsund@177
   383
        PlsqlBlock block = null;
chrislovsund@177
   384
chrislovsund@177
   385
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
   386
        if (sqlPlusLine(ts)) {
chrislovsund@177
   387
            return null;
chrislovsund@177
   388
        }
chrislovsund@177
   389
chrislovsund@362
   390
        boolean moveNext = ts.moveNext();
chrislovsund@362
   391
        Token<PlsqlTokenId> token = ts.token();
chrislovsund@362
   392
        Token<PlsqlTokenId> stmtBegin = current;
chrislovsund@177
   393
        boolean getName = true;
chrislovsund@177
   394
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@177
   395
        String name = current.text().toString();
subslk@401
   396
chrislovsund@177
   397
        while (moveNext) {
chrislovsund@177
   398
            String image = token.text().toString();
chrislovsund@177
   399
            PlsqlTokenId tokenID = token.id();
chrislovsund@177
   400
chrislovsund@177
   401
            if ((token != null) && (!image.equals(";")) && (!image.equals("/")) && (token.offset(tokenHierarchy) > endParse)) {
chrislovsund@177
   402
                break;
chrislovsund@177
   403
            }
chrislovsund@177
   404
chrislovsund@177
   405
            if (image.equals(";") || (image.equals("/") && checkForOnlyChar(ts, ts.offset()))) {
chrislovsund@177
   406
                block = new PlsqlBlock(stmtBegin.offset(tokenHierarchy), token.offset(tokenHierarchy), name.trim(), "", PlsqlBlockType.STATEMENT);
chrislovsund@177
   407
                checkPrefix(stmtBegin.offset(tokenHierarchy), ts, block);
chrislovsund@177
   408
                break;
chrislovsund@177
   409
            } else if (image.equalsIgnoreCase("CREATE")
chrislovsund@177
   410
                    || image.equalsIgnoreCase("DECLARE")
chrislovsund@177
   411
                    || image.equalsIgnoreCase("BEGIN")
chrislovsund@177
   412
                    || image.equalsIgnoreCase("WHEN")
chrislovsund@177
   413
                    || image.equalsIgnoreCase("THEN")
chrislovsund@177
   414
                    || image.equalsIgnoreCase("IF")
chrislovsund@177
   415
                    || image.equalsIgnoreCase("END")
chrislovsund@177
   416
                    || image.equalsIgnoreCase("ELSE")
chrislovsund@177
   417
                    || image.equalsIgnoreCase("LOOP")) {
chrislovsund@177
   418
                break;
chrislovsund@177
   419
            } else if (image.equalsIgnoreCase("CASE")) {
chrislovsund@177
   420
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
   421
                List children = checkCaseBlock(token, ts, lstChild, true);
chrislovsund@177
   422
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
   423
chrislovsund@177
   424
                    ts.move(beforeOff);
chrislovsund@177
   425
                    moveNext = ts.moveNext();
chrislovsund@177
   426
                } else {
chrislovsund@177
   427
                    for (int i = 0; i < children.size(); i++) {
chrislovsund@177
   428
                        PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@177
   429
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
   430
                            lstChild.add(child);
chrislovsund@177
   431
                        }
chrislovsund@177
   432
                    }
chrislovsund@177
   433
                }
chrislovsund@177
   434
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
   435
                //only single comment line
chrislovsund@177
   436
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
   437
                    customStartToken = token;
chrislovsund@177
   438
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
   439
                    if (customStartToken != null) {
chrislovsund@177
   440
                        if (ts.moveNext()) {
chrislovsund@177
   441
                            token = ts.token();
chrislovsund@177
   442
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@177
   443
                                    token.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
   444
                            customFoldBlocks.add(custom);
chrislovsund@177
   445
                        }
chrislovsund@177
   446
                        customStartToken = null;
chrislovsund@177
   447
                    }
chrislovsund@177
   448
                } else {
chrislovsund@177
   449
                    PlsqlBlock child = checkComment(token, ts);
chrislovsund@177
   450
                    if (child != null) {
chrislovsund@177
   451
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
   452
                            lstChild.add(child);
chrislovsund@177
   453
                        }
chrislovsund@177
   454
                    }
chrislovsund@177
   455
                }
chrislovsund@177
   456
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@177
   457
                int start = token.offset(tokenHierarchy);
chrislovsund@177
   458
                PlsqlBlock child = new PlsqlBlock(start,
chrislovsund@177
   459
                        start + token.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@177
   460
                if (child != null) {
chrislovsund@177
   461
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
   462
                        lstChild.add(child);
chrislovsund@177
   463
                    }
chrislovsund@177
   464
                }
chrislovsund@177
   465
            } else if (tokenID == PlsqlTokenId.WHITESPACE && image.contains("\n")) {
chrislovsund@177
   466
                getName = false;
chrislovsund@177
   467
            } else if (getName) {
chrislovsund@177
   468
                name = name + image;
chrislovsund@177
   469
            }
chrislovsund@177
   470
chrislovsund@177
   471
            moveNext = ts.moveNext();
chrislovsund@177
   472
            token = ts.token();
chrislovsund@177
   473
        }
chrislovsund@177
   474
chrislovsund@177
   475
        if (block != null) {
chrislovsund@177
   476
            //add children
chrislovsund@177
   477
            addChildren(block, lstChild, parentBlocks);
chrislovsund@177
   478
        }
chrislovsund@177
   479
chrislovsund@177
   480
        return block;
chrislovsund@177
   481
    }
chrislovsund@177
   482
chrislovsund@177
   483
    /**
chrislovsund@355
   484
     * Check whether the given token offset is included in any existing block
chrislovsund@362
   485
     *
chrislovsund@177
   486
     * @param token
chrislovsund@177
   487
     * @param immediateBlockHier
chrislovsund@177
   488
     * @param parent
chrislovsund@177
   489
     * @return
chrislovsund@177
   490
     */
chrislovsund@177
   491
    private boolean isTokenOk(Token<PlsqlTokenId> token, List<PlsqlBlock> immediateBlockHier, PlsqlBlock parent) {
chrislovsund@177
   492
        boolean isOk = true;
chrislovsund@177
   493
        int offset = token.offset(tokenHierarchy);
chrislovsund@177
   494
        for (int i = immediateBlockHier.size() - 1; i >= 0; i--) {
chrislovsund@177
   495
            PlsqlBlock block = immediateBlockHier.get(i);
chrislovsund@177
   496
            if ((block.getStartOffset() <= offset) && (block.getEndOffset() >= offset)) {
chrislovsund@177
   497
                isOk = false;
chrislovsund@177
   498
                break;
chrislovsund@177
   499
            }
chrislovsund@177
   500
        }
chrislovsund@177
   501
chrislovsund@177
   502
        if (isOk && parent != null) {
chrislovsund@177
   503
            if (!((parent.getStartOffset() <= offset) && (parent.getEndOffset() >= offset))) {
chrislovsund@177
   504
                isOk = false;
chrislovsund@177
   505
            }
chrislovsund@177
   506
        }
chrislovsund@177
   507
        return isOk;
chrislovsund@177
   508
    }
chrislovsund@177
   509
chrislovsund@177
   510
    /**
chrislovsund@177
   511
     * Method that will look for trigger blocks
chrislovsund@362
   512
     *
chrislovsund@177
   513
     * @param tempToken
chrislovsund@177
   514
     * @param ts
chrislovsund@177
   515
     * @param parentBlocks
chrislovsund@177
   516
     * @return
chrislovsund@177
   517
     */
chrislovsund@177
   518
    private PlsqlBlock checkTrigger(Token<PlsqlTokenId> tiggerToken, TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
   519
        Token<PlsqlTokenId> triggerBegin = tiggerToken;
chrislovsund@177
   520
        Token<PlsqlTokenId> tmp = tiggerToken;
chrislovsund@177
   521
        PlsqlBlock block = null;
chrislovsund@177
   522
        List<PlsqlBlock> lstChild = new ArrayList<PlsqlBlock>();
chrislovsund@177
   523
chrislovsund@177
   524
        String triggerName = "";
chrislovsund@177
   525
        boolean moveNext = false;
chrislovsund@177
   526
chrislovsund@177
   527
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
   528
        if (sqlPlusLine(ts)) {
chrislovsund@177
   529
            return null;
chrislovsund@177
   530
        }
chrislovsund@177
   531
chrislovsund@177
   532
        //Get procedure/function name which is the next non whitespace token
chrislovsund@177
   533
        moveNext = getNextNonWhitespace(ts, true);
chrislovsund@177
   534
        tmp = ts.token();
chrislovsund@177
   535
        if (moveNext == false) {
chrislovsund@177
   536
            return block;
chrislovsund@177
   537
        }
chrislovsund@177
   538
chrislovsund@177
   539
        triggerName = tmp.text().toString();
chrislovsund@177
   540
        triggerName = checkForOtherSchema(ts, triggerName);
chrislovsund@177
   541
        String alias = "";
chrislovsund@177
   542
        if (triggerName.indexOf('&') != -1) {
chrislovsund@177
   543
            alias = triggerName;
chrislovsund@177
   544
        }
chrislovsund@177
   545
        triggerName = getDefine(triggerName);
chrislovsund@177
   546
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@177
   547
chrislovsund@177
   548
        while (moveNext) {
chrislovsund@177
   549
            String image = tmp.text().toString();
chrislovsund@177
   550
            PlsqlTokenId tokenID = tmp.id();
chrislovsund@177
   551
chrislovsund@177
   552
            if ((tmp != null) && (!image.equals(";")) && (tmp.offset(tokenHierarchy) > endParse)) {
chrislovsund@177
   553
                break;
chrislovsund@177
   554
            }
chrislovsund@177
   555
chrislovsund@177
   556
            //We might have come to the end of the procedure/function declaration
chrislovsund@177
   557
            if ((tokenID == PlsqlTokenId.OPERATOR) && image.equals(";")) {
chrislovsund@177
   558
                //check whether previous Non white space token to the identifier is END
chrislovsund@177
   559
                int offset = ts.offset();
chrislovsund@177
   560
                getPreviousNonWhitespace(ts, true);
chrislovsund@177
   561
                Token<PlsqlTokenId> previousNWS = ts.token();
chrislovsund@177
   562
                String prevText = previousNWS.text().toString();
chrislovsund@177
   563
                getPreviousNonWhitespace(ts, true);
chrislovsund@177
   564
                previousNWS = ts.token();
chrislovsund@177
   565
                if (alias.equals("")) {
chrislovsund@177
   566
                    if ((prevText.equalsIgnoreCase(triggerName)
chrislovsund@177
   567
                            && previousNWS.text().toString().equalsIgnoreCase("END"))
chrislovsund@177
   568
                            || prevText.equalsIgnoreCase("END")) {
chrislovsund@177
   569
                        ts.move(offset);
chrislovsund@177
   570
                        moveNext = ts.moveNext();
chrislovsund@177
   571
                        moveNext = ts.moveNext();
chrislovsund@177
   572
                        block = new PlsqlBlock(triggerBegin.offset(tokenHierarchy),
chrislovsund@177
   573
                                ts.offset(), triggerName, alias, PlsqlBlockType.TRIGGER);
chrislovsund@177
   574
                        checkPrefix(triggerBegin.offset(tokenHierarchy), ts, block);
chrislovsund@177
   575
                        break;
chrislovsund@177
   576
                    }
chrislovsund@177
   577
                } else {
chrislovsund@177
   578
                    if ((prevText.equalsIgnoreCase(alias)
chrislovsund@177
   579
                            && previousNWS.text().toString().equalsIgnoreCase("END"))
chrislovsund@177
   580
                            || prevText.equalsIgnoreCase("END")) {
chrislovsund@177
   581
                        ts.move(offset);
chrislovsund@177
   582
                        moveNext = ts.moveNext();
chrislovsund@177
   583
                        moveNext = ts.moveNext();
chrislovsund@177
   584
                        block = new PlsqlBlock(triggerBegin.offset(tokenHierarchy),
chrislovsund@177
   585
                                ts.offset(), triggerName, alias, PlsqlBlockType.TRIGGER);
chrislovsund@177
   586
                        checkPrefix(triggerBegin.offset(tokenHierarchy), ts, block);
chrislovsund@177
   587
                        break;
chrislovsund@177
   588
                    }
chrislovsund@177
   589
                }
chrislovsund@177
   590
                ts.move(offset);
chrislovsund@177
   591
                moveNext = ts.moveNext();
chrislovsund@177
   592
            } else if (image.equalsIgnoreCase("TABLE")
chrislovsund@177
   593
                    || image.equalsIgnoreCase("INDEX")
chrislovsund@177
   594
                    || image.equalsIgnoreCase("SELECT")
chrislovsund@177
   595
                    || image.equalsIgnoreCase("UPDATE")
chrislovsund@177
   596
                    || image.equalsIgnoreCase("DELETE")
chrislovsund@177
   597
                    || image.equalsIgnoreCase("INSERT")
chrislovsund@177
   598
                    || image.equalsIgnoreCase("MERGE")
chrislovsund@177
   599
                    || image.equalsIgnoreCase("DROP")
chrislovsund@177
   600
                    || image.equalsIgnoreCase("SEQUENCE")) {
chrislovsund@177
   601
                if (!isNotBlockStart(tmp, ts)) {
chrislovsund@177
   602
                    int offset = tmp.offset(tokenHierarchy);
chrislovsund@177
   603
                    PlsqlBlock child = checkStatementBlock(tmp, ts, parentBlocks);
chrislovsund@177
   604
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
   605
chrislovsund@177
   606
                        ts.move(offset);
chrislovsund@177
   607
                        ts.moveNext();
chrislovsund@177
   608
                    } else {
chrislovsund@177
   609
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
   610
                            lstChild.add(child);
chrislovsund@177
   611
                        }
chrislovsund@177
   612
                    }
chrislovsund@177
   613
                }
chrislovsund@177
   614
            } else if (image.equalsIgnoreCase("PROCEDURE")) {
chrislovsund@177
   615
                int beforeOff = tmp.offset(tokenHierarchy);
chrislovsund@177
   616
                PlsqlBlock child = checkMethod(tmp, ts, PlsqlBlockType.PROCEDURE_IMPL, lstChild);
chrislovsund@177
   617
                if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
   618
                    ts.move(beforeOff);
chrislovsund@177
   619
                    ts.moveNext();
chrislovsund@177
   620
                } else {
chrislovsund@177
   621
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
   622
                        lstChild.add(child);
chrislovsund@177
   623
                    }
chrislovsund@177
   624
                }
chrislovsund@177
   625
            } //Inner procedure
chrislovsund@177
   626
            else if (image.equalsIgnoreCase("FUNCTION")) {
chrislovsund@177
   627
                int beforeOff = tmp.offset(tokenHierarchy);
chrislovsund@177
   628
                PlsqlBlock child = checkMethod(tmp, ts, PlsqlBlockType.FUNCTION_IMPL, lstChild);
chrislovsund@177
   629
                if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
   630
chrislovsund@177
   631
                    ts.move(beforeOff);
chrislovsund@177
   632
                    ts.moveNext();
chrislovsund@177
   633
                } else {
chrislovsund@177
   634
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
   635
                        lstChild.add(child);
chrislovsund@177
   636
                    }
chrislovsund@177
   637
                }
chrislovsund@177
   638
            } else if (image.equalsIgnoreCase("CREATE")
chrislovsund@177
   639
                    || image.equalsIgnoreCase("/")
chrislovsund@177
   640
                    || image.equalsIgnoreCase("PACKAGE")) {
chrislovsund@177
   641
                break;
chrislovsund@177
   642
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
   643
                //only single comment line
chrislovsund@177
   644
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
   645
                    customStartToken = tmp;
chrislovsund@177
   646
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
   647
                    if (customStartToken != null) {
chrislovsund@177
   648
                        String name = customStartToken.text().toString();
chrislovsund@177
   649
                        int index = name.toUpperCase(Locale.ENGLISH).indexOf("<FOLD>");
chrislovsund@177
   650
                        name = name.substring(index + 7).trim();
chrislovsund@177
   651
                        if (ts.moveNext()) {
chrislovsund@177
   652
                            tmp = ts.token();
chrislovsund@177
   653
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@177
   654
                                    tmp.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
   655
                            customFoldBlocks.add(custom);
chrislovsund@177
   656
                        }
chrislovsund@177
   657
                        customStartToken = null;
chrislovsund@177
   658
                    }
chrislovsund@177
   659
                } else {
chrislovsund@177
   660
                    PlsqlBlock child = checkComment(tmp, ts);
chrislovsund@177
   661
                    if (child != null) {
chrislovsund@177
   662
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
   663
                            lstChild.add(child);
chrislovsund@177
   664
                        }
chrislovsund@177
   665
                    }
chrislovsund@177
   666
                }
chrislovsund@177
   667
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@177
   668
                int start = tmp.offset(tokenHierarchy);
chrislovsund@177
   669
                PlsqlBlock child = new PlsqlBlock(start,
chrislovsund@177
   670
                        start + tmp.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@177
   671
                if (child != null) {
chrislovsund@177
   672
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
   673
                        lstChild.add(child);
chrislovsund@177
   674
                    }
chrislovsund@177
   675
                }
chrislovsund@177
   676
            }
chrislovsund@177
   677
chrislovsund@177
   678
            moveNext = ts.moveNext();
chrislovsund@177
   679
            tmp = ts.token();
chrislovsund@177
   680
        }
chrislovsund@177
   681
chrislovsund@177
   682
        if (block != null) {
chrislovsund@177
   683
            //add children
chrislovsund@177
   684
            addChildren(block, lstChild, parentBlocks);
chrislovsund@177
   685
        }
chrislovsund@177
   686
chrislovsund@177
   687
        return block;
chrislovsund@177
   688
    }
chrislovsund@177
   689
chrislovsund@177
   690
    /**
chrislovsund@177
   691
     * Method that will check the prefix of the given block and change the block values accordingly
chrislovsund@362
   692
     *
chrislovsund@177
   693
     * @param startOffset
chrislovsund@177
   694
     * @param ts
chrislovsund@177
   695
     * @param begin
chrislovsund@177
   696
     */
chrislovsund@177
   697
    private void checkPrefix(int startOffset, TokenSequence<PlsqlTokenId> ts, PlsqlBlock block) {
chrislovsund@177
   698
        String prefix = "";
chrislovsund@177
   699
        int offset = ts.offset();
chrislovsund@177
   700
        ts.move(startOffset);
chrislovsund@177
   701
        ts.moveNext();
chrislovsund@177
   702
        Token<PlsqlTokenId> token = ts.token();
chrislovsund@177
   703
        int beginOffset = startOffset;
chrislovsund@177
   704
chrislovsund@177
   705
        while (ts.movePrevious()) {
jrechtacek@0
   706
            token = ts.token();
jrechtacek@0
   707
            String image = token.text().toString();
chrislovsund@177
   708
chrislovsund@177
   709
            if (image.contains("\n") || (token.id() != PlsqlTokenId.KEYWORD && token.id() != PlsqlTokenId.WHITESPACE)) {
chrislovsund@177
   710
                break;
jrechtacek@0
   711
            }
chrislovsund@177
   712
chrislovsund@177
   713
            prefix = token.text().toString() + prefix;
chrislovsund@177
   714
            if (token.id() != PlsqlTokenId.WHITESPACE) {
chrislovsund@177
   715
                beginOffset = ts.offset();
chrislovsund@177
   716
            }
chrislovsund@177
   717
        }
chrislovsund@177
   718
chrislovsund@177
   719
        ts.move(offset);
chrislovsund@177
   720
        ts.moveNext();
chrislovsund@177
   721
        block.setStartOffset(beginOffset);
chrislovsund@177
   722
        block.setPrefix(prefix);
chrislovsund@177
   723
    }
chrislovsund@177
   724
chrislovsund@177
   725
    /**
chrislovsund@177
   726
     * Check whether there is a block existing with the given offset as the start offset
chrislovsund@362
   727
     *
chrislovsund@177
   728
     * @param blockHierarchy
chrislovsund@177
   729
     * @param offset
chrislovsund@177
   730
     * @return
chrislovsund@177
   731
     */
chrislovsund@177
   732
    private boolean isBlockStartExisting(List<PlsqlBlock> blockHierarchy, int offset) {
chrislovsund@177
   733
        boolean isExisting = false;
chrislovsund@177
   734
        for (int i = blockHierarchy.size() - 1; i >= 0; i--) {
chrislovsund@177
   735
            PlsqlBlock tmp = blockHierarchy.get(i);
chrislovsund@177
   736
            if (tmp.getStartOffset() == offset) {
chrislovsund@177
   737
                isExisting = true;
chrislovsund@177
   738
                break;
chrislovsund@177
   739
            }
chrislovsund@177
   740
chrislovsund@177
   741
            if (!isExisting) {
chrislovsund@177
   742
                if (isBlockStartExisting(tmp.getChildBlocks(), offset)) {
chrislovsund@177
   743
                    isExisting = true;
chrislovsund@177
   744
                    break;
chrislovsund@177
   745
                }
chrislovsund@177
   746
            }
chrislovsund@177
   747
        }
chrislovsund@177
   748
chrislovsund@177
   749
        return isExisting;
chrislovsund@177
   750
    }
chrislovsund@177
   751
chrislovsund@177
   752
    private boolean isEqual(PlsqlBlock parent, PlsqlBlock block) {
chrislovsund@177
   753
        if ((parent == null) || (block == null)) {
chrislovsund@177
   754
            return false;
chrislovsund@177
   755
        }
chrislovsund@177
   756
        if ((parent.getStartOffset() == block.getStartOffset())
chrislovsund@177
   757
                || (parent.getEndOffset() == block.getEndOffset())
chrislovsund@177
   758
                || (parent.getName().equalsIgnoreCase(block.getName()))) {
chrislovsund@177
   759
            return true;
chrislovsund@177
   760
        }
chrislovsund@177
   761
        return false;
chrislovsund@177
   762
    }
chrislovsund@177
   763
chrislovsund@177
   764
    private String readLine(TokenSequence<PlsqlTokenId> ts, Token<PlsqlTokenId> token) {
chrislovsund@177
   765
        String line = token.toString();
chrislovsund@177
   766
        while (ts.moveNext()) {
chrislovsund@177
   767
            token = ts.token();
chrislovsund@177
   768
            if (token.id() == PlsqlTokenId.WHITESPACE && token.text().toString().contains("\n")) {
chrislovsund@177
   769
                ts.movePrevious();
chrislovsund@177
   770
                break;
chrislovsund@177
   771
            }
chrislovsund@177
   772
chrislovsund@177
   773
            line = line + token.toString();
chrislovsund@177
   774
        }
chrislovsund@177
   775
chrislovsund@177
   776
        return line;
chrislovsund@177
   777
    }
chrislovsund@177
   778
chrislovsund@177
   779
    /**
chrislovsund@177
   780
     * Method that will remove the begin block of this declare block if there
chrislovsund@362
   781
     *
chrislovsund@177
   782
     * @param declareBlock
chrislovsund@177
   783
     */
chrislovsund@177
   784
    private void removeChildBegin(PlsqlBlock declareBlock) {
chrislovsund@177
   785
        //can check from the root hierarchies since begin/declare cannot be child blocks
chrislovsund@177
   786
        for (int i = blockHierarchy.size() - 1; i >= 0; i--) {
chrislovsund@177
   787
            PlsqlBlock tmp = blockHierarchy.get(i);
chrislovsund@177
   788
            if ((tmp.getStartOffset() > declareBlock.getStartOffset())
chrislovsund@177
   789
                    && (tmp.getEndOffset() == declareBlock.getEndOffset())
chrislovsund@177
   790
                    && (tmp.getType() == PlsqlBlockType.BEGIN_END)) {
chrislovsund@177
   791
                blockHierarchy.remove(tmp);
chrislovsund@177
   792
            }
chrislovsund@177
   793
        }
chrislovsund@177
   794
    }
chrislovsund@177
   795
chrislovsund@177
   796
    /**
chrislovsund@177
   797
     * Change offsets of the blocks below the area
chrislovsund@362
   798
     *
chrislovsund@177
   799
     * @param blockHier
chrislovsund@177
   800
     * @param endParse
chrislovsund@177
   801
     * @param length
chrislovsund@177
   802
     */
chrislovsund@177
   803
    private void changeOffSet(List<PlsqlBlock> blockHier, int offset, int length, boolean add, boolean adjust) {
chrislovsund@177
   804
        int count = blockHier.size();
chrislovsund@177
   805
        int start = 0;
chrislovsund@177
   806
        int end = 0;
chrislovsund@177
   807
        for (int i = 0; i < count; i++) {
chrislovsund@177
   808
            PlsqlBlock temp = blockHier.get(i);
chrislovsund@177
   809
            start = temp.getStartOffset();
chrislovsund@177
   810
            end = temp.getEndOffset();
chrislovsund@177
   811
            if (temp.getStartOffset() >= offset) {
chrislovsund@177
   812
                if (temp.getPreviousStart() == -1) {
chrislovsund@177
   813
                    temp.setPreviousStart(start);
chrislovsund@177
   814
                }
chrislovsund@177
   815
                if (start + length < 0) {
chrislovsund@177
   816
                    temp.setStartOffset(0);
chrislovsund@177
   817
                } else {
chrislovsund@177
   818
                    temp.setStartOffset(start + length);
chrislovsund@177
   819
                    if (startParse == start && adjust) //changing offsets of toBeRemoved
chrislovsund@177
   820
                    {
chrislovsund@177
   821
                        startParse = start + length;
chrislovsund@177
   822
                    }
chrislovsund@177
   823
                }
chrislovsund@177
   824
chrislovsund@177
   825
                if (temp.getPreviousEnd() == -1) {
chrislovsund@177
   826
                    temp.setPreviousEnd(end);
chrislovsund@177
   827
                }
chrislovsund@177
   828
                if (end + length < 0) {
chrislovsund@177
   829
                    temp.setEndOffset(0);
chrislovsund@177
   830
                } else {
chrislovsund@177
   831
                    temp.setEndOffset(end + length);
chrislovsund@177
   832
                    if (endParse == end && adjust) //changing offsets of toBeRemoved
chrislovsund@177
   833
                    {
chrislovsund@177
   834
                        endParse = end + length;
chrislovsund@177
   835
                    }
chrislovsund@177
   836
                }
chrislovsund@177
   837
chrislovsund@177
   838
                if (add) {
chrislovsund@177
   839
                    addToChangedBlocks(temp);
chrislovsund@177
   840
                }
chrislovsund@177
   841
                changeOffSet(temp.getChildBlocks(), offset, length, add, adjust);
chrislovsund@177
   842
            } else if (temp.getEndOffset() >= offset) {
chrislovsund@177
   843
                if (temp.getPreviousEnd() == -1) {
chrislovsund@177
   844
                    temp.setPreviousEnd(end);
chrislovsund@177
   845
                }
chrislovsund@177
   846
                if (end + length < 0) {
chrislovsund@177
   847
                    temp.setEndOffset(0);
chrislovsund@177
   848
                } else {
chrislovsund@177
   849
                    temp.setEndOffset(end + length);
chrislovsund@177
   850
                    if (endParse == end && adjust) //changing offsets of toBeRemoved
chrislovsund@177
   851
                    {
chrislovsund@177
   852
                        endParse = end + length;
chrislovsund@177
   853
                    }
chrislovsund@177
   854
                }
chrislovsund@177
   855
chrislovsund@177
   856
                if (add) {
chrislovsund@177
   857
                    addToChangedBlocks(temp);
chrislovsund@177
   858
                }
chrislovsund@177
   859
                changeOffSet(temp.getChildBlocks(), offset, length, add, adjust);
chrislovsund@177
   860
            }
chrislovsund@177
   861
        }
chrislovsund@177
   862
    }
chrislovsund@177
   863
chrislovsund@177
   864
    /**
chrislovsund@177
   865
     * Method that will check whether there are DEFINE statements in the affected area
chrislovsund@362
   866
     *
chrislovsund@177
   867
     * @param doc
chrislovsund@177
   868
     * @param startOffset
chrislovsund@177
   869
     * @param endOffset
chrislovsund@177
   870
     */
chrislovsund@177
   871
    private void checkAffected(Document doc, int startOffset, int endOffset) throws BadLocationException {
chrislovsund@177
   872
        int length = endOffset - startOffset;
chrislovsund@177
   873
        String changedText = doc.getText(startOffset, length);
chrislovsund@177
   874
chrislovsund@177
   875
        if ((changedText.toUpperCase(Locale.ENGLISH).indexOf("DEFINE ") != -1)
chrislovsund@177
   876
                || (changedText.toUpperCase(Locale.ENGLISH).indexOf("DEFIN ") != -1)
chrislovsund@177
   877
                || (changedText.toUpperCase(Locale.ENGLISH).indexOf("DEFI ") != -1)
chrislovsund@177
   878
                || (changedText.toUpperCase(Locale.ENGLISH).indexOf("DEF ") != -1)) {
chrislovsund@177
   879
            isDefineChanged = true;
chrislovsund@177
   880
        }
chrislovsund@177
   881
    }
chrislovsund@177
   882
chrislovsund@177
   883
    /**
chrislovsund@177
   884
     * Method that will make CURSOR blocks
chrislovsund@362
   885
     *
chrislovsund@177
   886
     * @param tempToken
chrislovsund@177
   887
     * @param ts
chrislovsund@177
   888
     * @param parentBlocks
chrislovsund@177
   889
     * @return
chrislovsund@177
   890
     */
chrislovsund@177
   891
    private PlsqlBlock checkCursor(Token<PlsqlTokenId> current, TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
   892
        Token<PlsqlTokenId> cursorBegin = current;
chrislovsund@177
   893
        Token<PlsqlTokenId> tmp = current;
chrislovsund@177
   894
        Token<PlsqlTokenId> cursorEnd = null;
chrislovsund@177
   895
        PlsqlBlock block = null;
chrislovsund@177
   896
        List<PlsqlBlock> lstChild = new ArrayList<PlsqlBlock>();
chrislovsund@177
   897
        boolean moveNext = false;
chrislovsund@177
   898
chrislovsund@177
   899
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
   900
        if (sqlPlusLine(ts)) {
chrislovsund@177
   901
            return null;
chrislovsund@177
   902
        }
chrislovsund@177
   903
chrislovsund@177
   904
        //Get next token which is the name
chrislovsund@177
   905
        int offset = ts.offset();
chrislovsund@177
   906
        moveNext = getNextNonWhitespace(ts, false);
chrislovsund@177
   907
        tmp = ts.token();
chrislovsund@177
   908
        if (moveNext == false) {
chrislovsund@177
   909
            ts.move(offset);
chrislovsund@177
   910
            ts.moveNext();
chrislovsund@177
   911
            return block;
chrislovsund@177
   912
        }
chrislovsund@177
   913
        String cursorName = tmp.text().toString();
chrislovsund@177
   914
        String alias = "";
chrislovsund@177
   915
        if (cursorName.indexOf('&') != -1) {
chrislovsund@177
   916
            alias = cursorName;
chrislovsund@177
   917
        }
chrislovsund@177
   918
        cursorName = getDefine(cursorName);
chrislovsund@177
   919
chrislovsund@177
   920
        //Next token has to be IS or ( if not leave
chrislovsund@177
   921
        moveNext = getNextNonWhitespace(ts, false);
chrislovsund@177
   922
        tmp = ts.token();
chrislovsund@177
   923
        boolean isFound = false;
chrislovsund@177
   924
        boolean parameter = false;
chrislovsund@177
   925
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@177
   926
chrislovsund@177
   927
        while (moveNext) {
chrislovsund@177
   928
            PlsqlTokenId tokenID = tmp.id();
chrislovsund@177
   929
            String image = tmp.text().toString();
chrislovsund@177
   930
chrislovsund@177
   931
            if ((tmp != null) && (!image.equals(";")) && (tmp.offset(tokenHierarchy) > endParse)) {
chrislovsund@177
   932
                break;
chrislovsund@177
   933
            }
chrislovsund@177
   934
chrislovsund@177
   935
            //When we have come up to ';' stop
chrislovsund@177
   936
            if ((tokenID == PlsqlTokenId.OPERATOR) && (image.equals(";"))) {
chrislovsund@177
   937
                if (isFound) {
chrislovsund@177
   938
                    if (ts.moveNext()) {
chrislovsund@177
   939
                        tmp = ts.token();
chrislovsund@177
   940
                    }
chrislovsund@177
   941
                    cursorEnd = tmp;
chrislovsund@177
   942
                    break;
chrislovsund@177
   943
                } else {
chrislovsund@177
   944
                    ts.move(offset);
chrislovsund@177
   945
                    ts.moveNext();
chrislovsund@177
   946
                    return null;
chrislovsund@177
   947
                }
chrislovsund@177
   948
            } else if ((tokenID == PlsqlTokenId.LPAREN) && (!isFound)) {
chrislovsund@177
   949
                parameter = true;
chrislovsund@177
   950
            } else if ((tokenID == PlsqlTokenId.RPAREN) && (!isFound)) {
chrislovsund@177
   951
                parameter = false;
chrislovsund@177
   952
            } else if (tokenID == PlsqlTokenId.KEYWORD) {
chrislovsund@177
   953
                if (image.equalsIgnoreCase("IS")) {
chrislovsund@177
   954
                    isFound = true;
chrislovsund@177
   955
                } else if ((!parameter) && //If this keyword is a parameter inside cursor ignore
chrislovsund@177
   956
                        ((image.equalsIgnoreCase("SUBTYPE"))
chrislovsund@177
   957
                        || (image.equalsIgnoreCase("CONSTANT"))
chrislovsund@177
   958
                        || (image.equalsIgnoreCase("NUMBER"))
chrislovsund@177
   959
                        || (image.equalsIgnoreCase("VARCHAR2")))) { //Avoid catching ';' of other statements
chrislovsund@177
   960
chrislovsund@177
   961
                    return null;
chrislovsund@177
   962
                } else if ((image.equalsIgnoreCase("VIEW"))
chrislovsund@177
   963
                        || (image.equalsIgnoreCase("PROCEDURE"))
chrislovsund@177
   964
                        || (image.equalsIgnoreCase("FUNCTION"))
chrislovsund@177
   965
                        || (image.equalsIgnoreCase("BEGIN"))
chrislovsund@177
   966
                        || (image.equalsIgnoreCase("DECLARE"))
chrislovsund@177
   967
                        || (image.equalsIgnoreCase("CREATE"))
chrislovsund@177
   968
                        || (image.equalsIgnoreCase("CURSOR"))
chrislovsund@177
   969
                        || (image.equalsIgnoreCase("EXCEPTION"))
chrislovsund@177
   970
                        || (image.equalsIgnoreCase("PRAGMA"))
chrislovsund@177
   971
                        || (image.equalsIgnoreCase("END"))
chrislovsund@177
   972
                        || (image.equalsIgnoreCase("COMMENT"))) { //Avoid catching ';' of other statements
chrislovsund@177
   973
chrislovsund@177
   974
                    return null;
chrislovsund@177
   975
                }
chrislovsund@177
   976
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
   977
                //only single comment line
chrislovsund@177
   978
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
   979
                    customStartToken = tmp;
chrislovsund@177
   980
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
   981
                    if (customStartToken != null) {
chrislovsund@177
   982
                        String name = customStartToken.text().toString();
chrislovsund@177
   983
                        int index = name.toUpperCase(Locale.ENGLISH).indexOf("<FOLD>");
chrislovsund@177
   984
                        name = name.substring(index + 7).trim();
chrislovsund@177
   985
                        if (ts.moveNext()) {
chrislovsund@177
   986
                            tmp = ts.token();
chrislovsund@177
   987
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@177
   988
                                    tmp.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
   989
                            customFoldBlocks.add(custom);
chrislovsund@177
   990
                        }
chrislovsund@177
   991
                        customStartToken = null;
chrislovsund@177
   992
                    }
chrislovsund@177
   993
                } else {
chrislovsund@177
   994
                    PlsqlBlock child = checkComment(tmp, ts);
chrislovsund@177
   995
                    if (child != null) {
chrislovsund@177
   996
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
   997
                            lstChild.add(child);
chrislovsund@177
   998
                        }
chrislovsund@177
   999
                    }
chrislovsund@177
  1000
                }
chrislovsund@177
  1001
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@177
  1002
                int start = tmp.offset(tokenHierarchy);
chrislovsund@177
  1003
                PlsqlBlock child = new PlsqlBlock(start,
chrislovsund@177
  1004
                        start + tmp.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@177
  1005
                if (child != null) {
chrislovsund@177
  1006
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  1007
                        lstChild.add(child);
chrislovsund@177
  1008
                    }
chrislovsund@177
  1009
                }
chrislovsund@177
  1010
            }
chrislovsund@177
  1011
chrislovsund@177
  1012
            moveNext = ts.moveNext();
chrislovsund@177
  1013
            tmp = ts.token();
chrislovsund@177
  1014
        }
chrislovsund@177
  1015
chrislovsund@177
  1016
        if (cursorEnd != null) {
chrislovsund@177
  1017
            block = new PlsqlBlock(cursorBegin.offset(tokenHierarchy), ts.offset(),
chrislovsund@177
  1018
                    cursorName, alias, PlsqlBlockType.CURSOR);
chrislovsund@177
  1019
        }
chrislovsund@177
  1020
chrislovsund@177
  1021
        if (block != null) {
chrislovsund@177
  1022
            //add children
chrislovsund@177
  1023
            addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  1024
        }
chrislovsund@177
  1025
chrislovsund@177
  1026
        return block;
chrislovsund@177
  1027
    }
chrislovsund@177
  1028
chrislovsund@177
  1029
    /**
chrislovsund@177
  1030
     * Check whether we have caught a begin of a declare block
chrislovsund@362
  1031
     *
chrislovsund@177
  1032
     * @param ts
chrislovsund@177
  1033
     * @param immediate
chrislovsund@177
  1034
     * @return
chrislovsund@177
  1035
     */
chrislovsund@177
  1036
    private boolean isDeclare(TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> immediate) {
chrislovsund@177
  1037
        int offset = ts.offset();
chrislovsund@177
  1038
        Token<PlsqlTokenId> token = ts.token();
chrislovsund@177
  1039
        Token<PlsqlTokenId> tokenPre = ts.token();
chrislovsund@177
  1040
chrislovsund@177
  1041
        while (ts.movePrevious()) {
jrechtacek@0
  1042
            token = ts.token();
jrechtacek@0
  1043
            String image = token.text().toString();
chrislovsund@177
  1044
            if (image.equalsIgnoreCase("DECLARE") && (!isBlockStartExisting(immediate, ts.offset()))) {
chrislovsund@177
  1045
                PlsqlBlock block = checkDeclareBlock(token, ts, immediate);
chrislovsund@177
  1046
                if (block != null && (checkExisting(block, immediate) == false)) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  1047
                    immediate.add(block);
chrislovsund@177
  1048
                    newBlocks.add(block);
chrislovsund@177
  1049
                } else {
chrislovsund@177
  1050
                    //Since we have not found the block we have to avoid getting caught up in a loop
chrislovsund@177
  1051
                    ts.move(offset);
chrislovsund@177
  1052
                    ts.moveNext();
chrislovsund@177
  1053
                }
chrislovsund@177
  1054
                return true;
chrislovsund@177
  1055
            } else if ((image.equals("/")) || (image.equalsIgnoreCase("BEGIN"))
chrislovsund@177
  1056
                    || ((image.equalsIgnoreCase("END")) && (tokenPre.text().toString().equals(";")))) {
chrislovsund@177
  1057
                break;
jrechtacek@0
  1058
            }
chrislovsund@177
  1059
chrislovsund@177
  1060
            if ((token.id() != PlsqlTokenId.WHITESPACE)
chrislovsund@177
  1061
                    && (token.id() != PlsqlTokenId.LINE_COMMENT)
chrislovsund@177
  1062
                    && (token.id() != PlsqlTokenId.BLOCK_COMMENT)) {
chrislovsund@177
  1063
                tokenPre = token;
jrechtacek@0
  1064
            }
chrislovsund@177
  1065
        }
chrislovsund@177
  1066
chrislovsund@177
  1067
        ts.move(offset);
chrislovsund@177
  1068
        ts.moveNext();
chrislovsund@177
  1069
        return false;
chrislovsund@177
  1070
    }
chrislovsund@177
  1071
chrislovsund@177
  1072
    /**
chrislovsund@355
  1073
     * Check whether the given block is already there in block hierarchy
chrislovsund@362
  1074
     *
chrislovsund@177
  1075
     * @param block
chrislovsund@177
  1076
     * @param childList
chrislovsund@177
  1077
     * @return
chrislovsund@177
  1078
     */
chrislovsund@177
  1079
    private boolean checkExisting(PlsqlBlock block, List<PlsqlBlock> childList) {
chrislovsund@177
  1080
        boolean existing = false;
chrislovsund@177
  1081
        int count = childList.size();
chrislovsund@177
  1082
        for (int i = 0; i < count; i++) {
chrislovsund@177
  1083
            PlsqlBlock tmp = childList.get(i);
chrislovsund@177
  1084
            if ((tmp.getName().equals(block.getName()) && tmp.getEndOffset() == block.getEndOffset())
chrislovsund@177
  1085
                    || (tmp.getName().equals(block.getName()) && tmp.getStartOffset() == block.getStartOffset())
chrislovsund@177
  1086
                    || (tmp.getEndOffset() == block.getEndOffset() && tmp.getStartOffset() == block.getStartOffset())) {
chrislovsund@177
  1087
                existing = true;
chrislovsund@177
  1088
                break;
jrechtacek@0
  1089
            }
chrislovsund@177
  1090
        }
chrislovsund@177
  1091
chrislovsund@177
  1092
        return existing;
chrislovsund@177
  1093
    }
chrislovsund@177
  1094
chrislovsund@177
  1095
    /**
chrislovsund@177
  1096
     * Clear internal variables used in a parse
chrislovsund@177
  1097
     */
chrislovsund@177
  1098
    private void clear() {
chrislovsund@177
  1099
        isDefineChanged = false;
chrislovsund@177
  1100
        startParse = 0;
chrislovsund@177
  1101
        endParse = 0;
chrislovsund@177
  1102
        changedLength = 0;
chrislovsund@177
  1103
        newBlocks = new ArrayList<PlsqlBlock>();
chrislovsund@177
  1104
        toBeRemoved = new ArrayList<PlsqlBlock>();
chrislovsund@177
  1105
        changedBlocks = new ArrayList<PlsqlBlock>();
chrislovsund@177
  1106
        unsuccessBlocks = new HashSet<Integer>();
chrislovsund@177
  1107
        resetPreviousValues(blockHierarchy);
chrislovsund@177
  1108
    }
chrislovsund@177
  1109
chrislovsund@177
  1110
    private void resetPreviousValues(List<PlsqlBlock> blockList) {
chrislovsund@177
  1111
        for (PlsqlBlock block : blockList) {
chrislovsund@177
  1112
            block.setPreviousStart(-1);
chrislovsund@177
  1113
            block.setPreviousEnd(-1);
chrislovsund@177
  1114
            resetPreviousValues(block.getChildBlocks());
chrislovsund@177
  1115
        }
chrislovsund@177
  1116
    }
chrislovsund@177
  1117
chrislovsund@177
  1118
    public void beforeCaseChange() {
chrislovsund@177
  1119
        caseChangeInProgress = true;
chrislovsund@177
  1120
    }
chrislovsund@177
  1121
chrislovsund@177
  1122
    public void afterCaseChange() {
chrislovsund@177
  1123
        caseChangeInProgress = false;
chrislovsund@177
  1124
    }
chrislovsund@177
  1125
chrislovsund@177
  1126
    public void beforeSave(Document document) {
chrislovsund@177
  1127
        saveInProgress = true;
chrislovsund@177
  1128
        synchronized (updateLock) {
chrislovsund@177
  1129
            updateEvents.clear();
chrislovsund@177
  1130
        }
chrislovsund@177
  1131
    }
chrislovsund@177
  1132
chrislovsund@177
  1133
    public boolean isSaveInProgress() {
chrislovsund@177
  1134
        return saveInProgress || caseChangeInProgress;
chrislovsund@177
  1135
    }
chrislovsund@177
  1136
chrislovsund@177
  1137
    public synchronized void afterSave(Document document) {
chrislovsund@177
  1138
        setChanged();
chrislovsund@177
  1139
        //initHierarchy(document);
chrislovsund@177
  1140
        reParse(document);
chrislovsund@177
  1141
        parseAliases();
chrislovsund@177
  1142
        notifyObservers(document);
chrislovsund@177
  1143
        clearChanged();
chrislovsund@177
  1144
        saveInProgress = false;
chrislovsund@177
  1145
    }
chrislovsund@177
  1146
chrislovsund@177
  1147
    private EventProperties addNewEvent(DocumentEvent e, DocumentEvent.EventType mode) {
chrislovsund@177
  1148
        EventProperties eventProperties = new EventProperties(this);
chrislovsund@177
  1149
        eventProperties.document = e.getDocument();
chrislovsund@177
  1150
        eventProperties.offset = e.getOffset();
chrislovsund@177
  1151
        eventProperties.length = e.getLength();
chrislovsund@177
  1152
        eventProperties.mode = mode;
chrislovsund@177
  1153
        updateEvents.addLast(eventProperties);
chrislovsund@177
  1154
        return eventProperties;
chrislovsund@177
  1155
chrislovsund@177
  1156
    }
chrislovsund@177
  1157
chrislovsund@177
  1158
    private void removeBlock(PlsqlBlock block, List<PlsqlBlock> lstBlocks) {
chrislovsund@177
  1159
        boolean removed = false;
chrislovsund@177
  1160
        if (!lstBlocks.remove(block)) {
chrislovsund@177
  1161
            if (removeBlock(blockHierarchy, block)) {
chrislovsund@177
  1162
                toBeRemoved.add(block);
chrislovsund@177
  1163
                removed = true;
jrechtacek@0
  1164
            }
chrislovsund@177
  1165
        } else {
jrechtacek@0
  1166
            toBeRemoved.add(block);
jrechtacek@0
  1167
            removed = true;
chrislovsund@177
  1168
        }
chrislovsund@177
  1169
chrislovsund@177
  1170
        if (removed) {
chrislovsund@177
  1171
            //If this block is there in changed blocks remove it
chrislovsund@177
  1172
            removeBlock(changedBlocks, block);
chrislovsund@177
  1173
            if (startParse > block.getStartOffset()) {
chrislovsund@177
  1174
                startParse = block.getStartOffset();
jrechtacek@0
  1175
            }
chrislovsund@177
  1176
            if (endParse < block.getEndOffset()) {
chrislovsund@177
  1177
                endParse = block.getEndOffset();
jrechtacek@0
  1178
            }
chrislovsund@177
  1179
        }
chrislovsund@177
  1180
    }
chrislovsund@177
  1181
chrislovsund@177
  1182
    private void addToChangedBlocks(PlsqlBlock temp) {
chrislovsund@177
  1183
        int count = changedBlocks.size();
chrislovsund@177
  1184
        boolean found = false;
chrislovsund@177
  1185
        for (int i = 0; i < count; i++) {
chrislovsund@177
  1186
            PlsqlBlock tmp = changedBlocks.get(i);
chrislovsund@177
  1187
            if (tmp.getStartOffset() == temp.getStartOffset() && tmp.getEndOffset() == temp.getEndOffset()) {
chrislovsund@177
  1188
                found = true;
chrislovsund@177
  1189
                break;
chrislovsund@177
  1190
            }
chrislovsund@177
  1191
        }
chrislovsund@177
  1192
chrislovsund@177
  1193
        if (!found) {
chrislovsund@177
  1194
            changedBlocks.add(temp);
chrislovsund@177
  1195
        }
chrislovsund@177
  1196
    }
chrislovsund@177
  1197
chrislovsund@177
  1198
    private String checkForOtherSchema(TokenSequence<PlsqlTokenId> ts, String currentName) {
chrislovsund@177
  1199
        int offset = ts.offset();
chrislovsund@177
  1200
        if (ts.moveNext()) {
chrislovsund@177
  1201
            Token<PlsqlTokenId> token = ts.token();
chrislovsund@177
  1202
            if (token.id() == PlsqlTokenId.DOT) {
chrislovsund@177
  1203
                if (ts.moveNext()) {
chrislovsund@177
  1204
                    token = ts.token();
chrislovsund@177
  1205
                    if (token.id() == PlsqlTokenId.DOT) {
chrislovsund@177
  1206
                        if (ts.moveNext()) {
chrislovsund@177
  1207
                            return ts.token().toString();
chrislovsund@177
  1208
                        }
chrislovsund@177
  1209
                    } else {
chrislovsund@177
  1210
                        return ts.token().toString();
chrislovsund@177
  1211
                    }
chrislovsund@177
  1212
                }
chrislovsund@177
  1213
            }
chrislovsund@177
  1214
        }
chrislovsund@177
  1215
chrislovsund@177
  1216
        //Reset the original location
chrislovsund@177
  1217
        ts.move(offset);
chrislovsund@177
  1218
        ts.moveNext();
chrislovsund@177
  1219
chrislovsund@177
  1220
        return currentName;
chrislovsund@177
  1221
    }
chrislovsund@177
  1222
chrislovsund@177
  1223
    private static class EventProperties {
chrislovsund@177
  1224
chrislovsund@177
  1225
        public int offset = -1;
chrislovsund@177
  1226
        public int length = -1;
chrislovsund@177
  1227
        public Document document = null;
chrislovsund@177
  1228
        DocumentEvent.EventType mode = null;
chrislovsund@177
  1229
        public PlsqlBlockFactory blockFactory = null;
chrislovsund@177
  1230
chrislovsund@177
  1231
        public EventProperties(PlsqlBlockFactory blockFactory) {
chrislovsund@177
  1232
            this.blockFactory = blockFactory;
chrislovsund@177
  1233
        }
chrislovsund@177
  1234
    }
chrislovsund@177
  1235
chrislovsund@177
  1236
    private static class UpdateBlocksThread implements Runnable {
chrislovsund@177
  1237
chrislovsund@177
  1238
        @Override
chrislovsund@177
  1239
        public void run() {
chrislovsund@177
  1240
            synchronized (updateLock) {
chrislovsund@177
  1241
                while (updateEvents.size() > 0) {
chrislovsund@177
  1242
                    EventProperties event = updateEvents.getFirst();
chrislovsund@177
  1243
                    Document doc = event.document;
chrislovsund@177
  1244
                    List<EventProperties> docList = new ArrayList<EventProperties>();
chrislovsund@177
  1245
chrislovsund@177
  1246
                    while (event != null && event.document.equals(doc)) {
chrislovsund@177
  1247
                        updateEvents.removeFirst();
chrislovsund@177
  1248
                        docList.add(event);
chrislovsund@177
  1249
                        event = null;
chrislovsund@177
  1250
                        if (updateEvents.size() > 0) {
chrislovsund@177
  1251
                            event = updateEvents.getFirst();
chrislovsund@177
  1252
                        }
chrislovsund@177
  1253
                    }
chrislovsund@177
  1254
chrislovsund@177
  1255
                    docList.get(0).blockFactory.doUpdate(doc, docList);
chrislovsund@177
  1256
                }
chrislovsund@177
  1257
            }
chrislovsund@177
  1258
        }
chrislovsund@177
  1259
    }
chrislovsund@177
  1260
chrislovsund@177
  1261
    private synchronized void doUpdate(final Document document, final List<EventProperties> docList) {
chrislovsund@362
  1262
        LOG.log(Level.FINE, "doUpdate", new Object[]{document, docList});
chrislovsund@177
  1263
chrislovsund@177
  1264
        //make sure that the updates are run in the Swing thread
chrislovsund@177
  1265
        SwingUtilities.invokeLater(new Runnable() {
chrislovsund@177
  1266
            @Override
chrislovsund@177
  1267
            public void run() {
chrislovsund@177
  1268
                setChanged();
chrislovsund@177
  1269
                updateBlocks(document, docList);
chrislovsund@177
  1270
                parseAliases();
chrislovsund@177
  1271
                notifyObservers(document);
chrislovsund@177
  1272
                clearChanged();
chrislovsund@177
  1273
            }
chrislovsund@177
  1274
        });
chrislovsund@177
  1275
    }
chrislovsund@177
  1276
chrislovsund@177
  1277
    private void addUpdateEvent(DocumentEvent e, DocumentEvent.EventType mode) {
chrislovsund@177
  1278
        synchronized (updateLock) {
chrislovsund@177
  1279
            if (updateBlocksTask == null) {
chrislovsund@177
  1280
                updateBlocksTask = RP.create(new UpdateBlocksThread());
chrislovsund@177
  1281
            }
chrislovsund@177
  1282
            updateBlocksTask.schedule(DEFAULT_WAIT_TIME);
chrislovsund@177
  1283
            addNewEvent(e, mode);
chrislovsund@177
  1284
        }
chrislovsund@177
  1285
    }
chrislovsund@177
  1286
chrislovsund@177
  1287
    /**
chrislovsund@177
  1288
     * Event fired on insert
chrislovsund@362
  1289
     *
chrislovsund@177
  1290
     * @param e
chrislovsund@177
  1291
     */
chrislovsund@177
  1292
    @Override
chrislovsund@177
  1293
    public void insertUpdate(DocumentEvent e) {
chrislovsund@362
  1294
        LOG.log(Level.FINER, "insertUpdate", e);
chrislovsund@177
  1295
        if (isSaveInProgress()) {
chrislovsund@177
  1296
            return;
chrislovsund@177
  1297
        }
chrislovsund@177
  1298
        addUpdateEvent(e, DocumentEvent.EventType.INSERT);
chrislovsund@177
  1299
    }
chrislovsund@177
  1300
chrislovsund@177
  1301
    /**
chrislovsund@177
  1302
     * Event fired in remove
chrislovsund@362
  1303
     *
chrislovsund@177
  1304
     * @param e
chrislovsund@177
  1305
     */
chrislovsund@177
  1306
    @Override
chrislovsund@177
  1307
    public void removeUpdate(DocumentEvent e) {
chrislovsund@362
  1308
        LOG.log(Level.FINER, "removeUpdate", e);
chrislovsund@177
  1309
        if (isSaveInProgress()) {
chrislovsund@177
  1310
            return;
chrislovsund@177
  1311
        }
chrislovsund@177
  1312
        addUpdateEvent(e, DocumentEvent.EventType.REMOVE);
chrislovsund@177
  1313
    }
chrislovsund@177
  1314
chrislovsund@177
  1315
    /**
chrislovsund@355
  1316
     * triggered when opening a different document
chrislovsund@362
  1317
     *
chrislovsund@177
  1318
     * @param e
chrislovsund@177
  1319
     */
chrislovsund@177
  1320
    @Override
chrislovsund@177
  1321
    public void changedUpdate(DocumentEvent e) {
chrislovsund@177
  1322
        //It seems we don't have to handle this case since initHierarchy
chrislovsund@177
  1323
        // will always be called before this
chrislovsund@177
  1324
    }
chrislovsund@177
  1325
chrislovsund@177
  1326
    /**
chrislovsund@177
  1327
     * Update block hierarchy on a document event
chrislovsund@362
  1328
     *
chrislovsund@177
  1329
     * @param e
chrislovsund@177
  1330
     * @param action
chrislovsund@177
  1331
     */
chrislovsund@177
  1332
    public synchronized void initHierarchy(Document doc) {
chrislovsund@177
  1333
        clear();
chrislovsund@177
  1334
chrislovsund@177
  1335
        if (doc == null) {
chrislovsund@177
  1336
            return;
chrislovsund@177
  1337
        }
chrislovsund@177
  1338
chrislovsund@177
  1339
        docStartOffset = doc.getStartPosition().getOffset();
chrislovsund@177
  1340
        docEndOffset = doc.getEndPosition().getOffset();
chrislovsund@177
  1341
        Object obj = doc.getProperty("Listener");
chrislovsund@177
  1342
chrislovsund@177
  1343
        if ((obj == null) || (!obj.equals("YES"))) {
chrislovsund@177
  1344
            startParse = docStartOffset;
chrislovsund@177
  1345
            endParse = docEndOffset - 1;
chrislovsund@177
  1346
chrislovsund@177
  1347
            //clean block hierarchy
chrislovsund@177
  1348
            blockHierarchy.clear();
chrislovsund@177
  1349
            customFoldBlocks.clear();
chrislovsund@177
  1350
            getAliases(doc);
chrislovsund@177
  1351
            generateBlocks(doc);
chrislovsund@177
  1352
            //This property is added only to ensure that document listener is added only once
chrislovsund@177
  1353
            doc.putProperty("Listener", "YES");
chrislovsund@177
  1354
            doc.addDocumentListener(this);
chrislovsund@177
  1355
        }
chrislovsund@177
  1356
    }
chrislovsund@177
  1357
chrislovsund@177
  1358
    /**
chrislovsund@177
  1359
     * Method that will return the block within the start & end parse
chrislovsund@362
  1360
     *
chrislovsund@177
  1361
     * @param start
chrislovsund@177
  1362
     * @param end
chrislovsund@177
  1363
     * @return
chrislovsund@177
  1364
     */
chrislovsund@177
  1365
    private PlsqlBlock getParentBlock(List<PlsqlBlock> lstBlock, int start, int end) {
chrislovsund@177
  1366
        PlsqlBlock parent = null;
chrislovsund@177
  1367
        int count = lstBlock.size();
chrislovsund@177
  1368
        for (int i = 0; i < count; i++) {
chrislovsund@177
  1369
            PlsqlBlock tmp = lstBlock.get(i);
chrislovsund@177
  1370
            if ((tmp.getStartOffset() < start) && (tmp.getEndOffset() > end)) {
chrislovsund@177
  1371
                PlsqlBlock child = getParentBlock(tmp.getChildBlocks(), start, end);
chrislovsund@177
  1372
                if (child != null) {
chrislovsund@177
  1373
                    parent = child;
chrislovsund@177
  1374
                } else {
chrislovsund@177
  1375
                    parent = tmp;
chrislovsund@177
  1376
                }
chrislovsund@177
  1377
chrislovsund@177
  1378
                break;
chrislovsund@177
  1379
            }
chrislovsund@177
  1380
        }
chrislovsund@177
  1381
chrislovsund@177
  1382
        return parent;
chrislovsund@177
  1383
    }
chrislovsund@177
  1384
chrislovsund@177
  1385
    /**
chrislovsund@177
  1386
     * Get the line offset of the beginning of this block end line
chrislovsund@362
  1387
     *
chrislovsund@177
  1388
     * @param doc
chrislovsund@177
  1389
     * @param parent
chrislovsund@177
  1390
     * @return
chrislovsund@177
  1391
     */
chrislovsund@177
  1392
    private int getPreLineOfBlockEnd(Document doc, PlsqlBlock parent) {
chrislovsund@177
  1393
        TokenHierarchy tokenHier = TokenHierarchy.get(doc);
chrislovsund@177
  1394
        @SuppressWarnings("unchecked")
chrislovsund@177
  1395
        TokenSequence<PlsqlTokenId> ts = tokenHier.tokenSequence(PlsqlTokenId.language());
chrislovsund@177
  1396
        if (ts == null) {
chrislovsund@177
  1397
            return parent.getEndOffset();
chrislovsund@177
  1398
        }
chrislovsund@177
  1399
        int preEnd = parent.getEndOffset();
chrislovsund@177
  1400
chrislovsund@177
  1401
        //go to the previous line break
chrislovsund@177
  1402
        ts.move(preEnd);
chrislovsund@177
  1403
        boolean movePrevious = ts.movePrevious();
chrislovsund@177
  1404
        Token<PlsqlTokenId> tokenPre = ts.token();
chrislovsund@177
  1405
chrislovsund@177
  1406
        while (movePrevious) {
chrislovsund@177
  1407
            if (tokenPre.text().toString().contains("\n")) {
chrislovsund@177
  1408
                preEnd = tokenPre.offset(tokenHier);
chrislovsund@177
  1409
                break;
chrislovsund@177
  1410
            }
chrislovsund@177
  1411
            movePrevious = ts.movePrevious();
chrislovsund@177
  1412
            tokenPre = ts.token();
chrislovsund@177
  1413
        }
chrislovsund@177
  1414
chrislovsund@177
  1415
        return preEnd;
chrislovsund@177
  1416
    }
chrislovsund@177
  1417
chrislovsund@177
  1418
    private boolean isNotBlockStart(Token<PlsqlTokenId> current, TokenSequence<PlsqlTokenId> ts) {
chrislovsund@177
  1419
        boolean isNotBlockStart = false;
chrislovsund@177
  1420
        int offset = current.offset(tokenHierarchy);
chrislovsund@177
  1421
        Token<PlsqlTokenId> token = current;
chrislovsund@177
  1422
        Token<PlsqlTokenId> tokenPre = current;
chrislovsund@177
  1423
        int loopCount = 0;
chrislovsund@177
  1424
        while (ts.movePrevious()) {
chrislovsund@177
  1425
            token = ts.token();
chrislovsund@177
  1426
chrislovsund@177
  1427
            if (loopCount == 0 && token.id() == PlsqlTokenId.DOT) {
chrislovsund@177
  1428
                isNotBlockStart = true;
chrislovsund@177
  1429
                break;
chrislovsund@177
  1430
            } else if (token.id() == PlsqlTokenId.WHITESPACE) {
chrislovsund@177
  1431
                String preText = tokenPre.text().toString();
chrislovsund@177
  1432
                if (token.text().toString().contains("\n")) {
chrislovsund@177
  1433
                    if (preText.equalsIgnoreCase("TYPE")
chrislovsund@177
  1434
                            || preText.equalsIgnoreCase("GRANT")) {
chrislovsund@177
  1435
                        isNotBlockStart = true;
chrislovsund@177
  1436
                    }
chrislovsund@177
  1437
                    break;
chrislovsund@177
  1438
                }
chrislovsund@177
  1439
            } else if (token.text().toString().equalsIgnoreCase("TYPE")) {
chrislovsund@177
  1440
                isNotBlockStart = true;
chrislovsund@177
  1441
                break;
chrislovsund@177
  1442
            } else {
chrislovsund@177
  1443
                tokenPre = token;
chrislovsund@177
  1444
            }
chrislovsund@177
  1445
            loopCount++;
chrislovsund@177
  1446
        }
chrislovsund@177
  1447
chrislovsund@177
  1448
        if (token.text().toString().equalsIgnoreCase("TYPE")
chrislovsund@177
  1449
                || token.text().toString().equalsIgnoreCase("GRANT")) {
chrislovsund@177
  1450
            isNotBlockStart = true;
chrislovsund@177
  1451
        }
chrislovsund@177
  1452
chrislovsund@177
  1453
        ts.move(offset);
chrislovsund@177
  1454
        ts.moveNext();
chrislovsund@177
  1455
        return isNotBlockStart;
chrislovsund@177
  1456
    }
chrislovsund@177
  1457
chrislovsund@177
  1458
    /**
chrislovsund@177
  1459
     * Get the line offset of the second line of this block start
chrislovsund@362
  1460
     *
chrislovsund@177
  1461
     * @param doc
chrislovsund@177
  1462
     * @param parent
chrislovsund@177
  1463
     * @return
chrislovsund@177
  1464
     */
chrislovsund@177
  1465
    private int getSecondLineOfBlock(Document doc, PlsqlBlock parent) {
chrislovsund@177
  1466
        TokenHierarchy tokenHier = TokenHierarchy.get(doc);
chrislovsund@177
  1467
        @SuppressWarnings("unchecked")
chrislovsund@177
  1468
        TokenSequence<PlsqlTokenId> ts = tokenHier.tokenSequence(PlsqlTokenId.language());
chrislovsund@177
  1469
        if (ts == null) {
chrislovsund@177
  1470
            return parent.getStartOffset();
chrislovsund@177
  1471
        }
chrislovsund@177
  1472
        int preStart = parent.getStartOffset();
chrislovsund@177
  1473
        ts.move(preStart);
chrislovsund@177
  1474
        boolean moveNext = ts.moveNext();
chrislovsund@177
  1475
        Token<PlsqlTokenId> tokenNext = ts.token();
chrislovsund@177
  1476
chrislovsund@177
  1477
        while (moveNext) {
chrislovsund@177
  1478
            if (tokenNext.text().toString().contains("\n")) {
chrislovsund@177
  1479
                preStart = tokenNext.offset(tokenHier);
chrislovsund@177
  1480
                break;
chrislovsund@177
  1481
            }
chrislovsund@177
  1482
            moveNext = ts.moveNext();
chrislovsund@177
  1483
            tokenNext = ts.token();
chrislovsund@177
  1484
        }
chrislovsund@177
  1485
chrislovsund@177
  1486
        return preStart;
chrislovsund@177
  1487
    }
chrislovsund@177
  1488
chrislovsund@177
  1489
    /**
chrislovsund@177
  1490
     * If any defines are changed change the affected names
chrislovsund@177
  1491
     */
chrislovsund@177
  1492
    private void parseAliases() {
chrislovsund@177
  1493
        if (!isDefineChanged) {
chrislovsund@177
  1494
            return;
chrislovsund@177
  1495
        }
chrislovsund@177
  1496
chrislovsund@177
  1497
        int size = blockHierarchy.size();
chrislovsund@177
  1498
        for (int i = 0; i < size; i++) {
chrislovsund@177
  1499
            PlsqlBlock block = blockHierarchy.get(i);
chrislovsund@177
  1500
            evaluateBlock(block);
chrislovsund@177
  1501
        }
chrislovsund@177
  1502
    }
chrislovsund@177
  1503
chrislovsund@177
  1504
    public boolean isAliasesChanged() {
chrislovsund@177
  1505
        return isDefineChanged;
chrislovsund@177
  1506
    }
chrislovsund@177
  1507
chrislovsund@177
  1508
    /**
chrislovsund@362
  1509
     * Method that will evaluate the given block and decide whether the name has to be changed
chrislovsund@362
  1510
     *
chrislovsund@177
  1511
     * @param block
chrislovsund@177
  1512
     */
chrislovsund@177
  1513
    private void evaluateBlock(PlsqlBlock block) {
chrislovsund@177
  1514
        String alias = block.getAlias();
chrislovsund@177
  1515
        if (!alias.equals("")) {
chrislovsund@177
  1516
            block.setName(getDefine(alias));
chrislovsund@177
  1517
        }
chrislovsund@177
  1518
chrislovsund@177
  1519
        int childCount = block.getChildBlocks().size();
chrislovsund@177
  1520
        for (int i = 0; i < childCount; i++) {
chrislovsund@177
  1521
            PlsqlBlock child = block.getChildBlocks().get(i);
chrislovsund@177
  1522
            evaluateBlock(child);
chrislovsund@177
  1523
        }
chrislovsund@177
  1524
    }
chrislovsund@177
  1525
chrislovsund@177
  1526
    /**
chrislovsund@177
  1527
     * Remove given block from the hierarchy
chrislovsund@362
  1528
     *
chrislovsund@177
  1529
     * @param blockHier
chrislovsund@177
  1530
     * @param block
chrislovsund@177
  1531
     */
chrislovsund@177
  1532
    private boolean removeBlock(List<PlsqlBlock> blockHier, PlsqlBlock block) {
chrislovsund@177
  1533
        int count = blockHier.size();
chrislovsund@177
  1534
        boolean isFound = false;
chrislovsund@177
  1535
chrislovsund@177
  1536
        for (int i = 0; i < count; i++) {
chrislovsund@177
  1537
            PlsqlBlock temp = blockHier.get(i);
chrislovsund@177
  1538
chrislovsund@177
  1539
            if ((temp.getStartOffset() == block.getStartOffset())
chrislovsund@177
  1540
                    && (temp.getEndOffset() == block.getEndOffset())) {
chrislovsund@177
  1541
                blockHier.remove(temp);
chrislovsund@177
  1542
                isFound = true;
chrislovsund@177
  1543
                break;
chrislovsund@177
  1544
            } else {
chrislovsund@177
  1545
                if ((temp.getStartOffset() < block.getStartOffset())
chrislovsund@177
  1546
                        && (temp.getEndOffset() > block.getEndOffset())) { //block is a child
chrislovsund@177
  1547
chrislovsund@177
  1548
                    if (removeBlock(temp.getChildBlocks(), block)) {
chrislovsund@177
  1549
                        isFound = true;
chrislovsund@177
  1550
                        break;
chrislovsund@177
  1551
                    }
chrislovsund@177
  1552
                }
chrislovsund@177
  1553
            }
chrislovsund@177
  1554
        }
chrislovsund@177
  1555
chrislovsund@177
  1556
        return isFound;
chrislovsund@177
  1557
    }
chrislovsund@177
  1558
chrislovsund@177
  1559
    /**
chrislovsund@362
  1560
     * Add child blocks enclosed by the change area to the remove list (do not update the parse area here, done only in
chrislovsund@362
  1561
     * REMOVE)
chrislovsund@362
  1562
     *
chrislovsund@177
  1563
     * @param doc
chrislovsund@177
  1564
     * @param plsqlBlocks
chrislovsund@177
  1565
     * @param toBeRemoved
chrislovsund@177
  1566
     * @param startOffset
chrislovsund@177
  1567
     * @param endOffset
chrislovsund@177
  1568
     * @return
chrislovsund@177
  1569
     */
chrislovsund@177
  1570
    private void removeEnclosedBlocks(Document doc, List<PlsqlBlock> plsqlBlocks, int startOffset, int endOffset) {
chrislovsund@177
  1571
        int count = plsqlBlocks.size();
chrislovsund@177
  1572
chrislovsund@177
  1573
        for (int i = count - 1; i >= 0; i--) {
chrislovsund@177
  1574
            PlsqlBlock block = plsqlBlocks.get(i);
chrislovsund@177
  1575
chrislovsund@177
  1576
            if ((block.getEndOffset() <= endOffset)
chrislovsund@177
  1577
                    && (block.getStartOffset() >= startOffset)) { //blocks which are enclosed by the affected area
chrislovsund@177
  1578
                removeBlock(block, plsqlBlocks);
chrislovsund@177
  1579
            } else {
chrislovsund@177
  1580
                removeEnclosedBlocks(doc, block.getChildBlocks(), startOffset, endOffset);
chrislovsund@177
  1581
            }
chrislovsund@177
  1582
        }
chrislovsund@177
  1583
    }
chrislovsund@177
  1584
chrislovsund@177
  1585
    /**
chrislovsund@362
  1586
     * Add child blocks affected by the change area to the remove list and update the parse area
chrislovsund@362
  1587
     *
chrislovsund@177
  1588
     * @param doc
chrislovsund@177
  1589
     * @param plsqlBlocks
chrislovsund@177
  1590
     * @param toBeRemoved
chrislovsund@177
  1591
     * @param startOffset
chrislovsund@177
  1592
     * @param endOffset
chrislovsund@177
  1593
     * @return
chrislovsund@177
  1594
     */
chrislovsund@177
  1595
    private boolean removeBlocksWithin(Document doc, List<PlsqlBlock> plsqlBlocks, int startOffset, int endOffset) {
chrislovsund@177
  1596
        boolean blockIsFound = false;
chrislovsund@177
  1597
chrislovsund@177
  1598
        int count = plsqlBlocks.size();
chrislovsund@177
  1599
chrislovsund@177
  1600
        for (int i = count - 1; i >= 0; i--) {
chrislovsund@177
  1601
            PlsqlBlock block = plsqlBlocks.get(i);
chrislovsund@177
  1602
            int blockStart = block.getStartOffset();
chrislovsund@177
  1603
            int blockEnd = block.getEndOffset();
chrislovsund@177
  1604
            //assumption on max length of a package/procedure/function first line
chrislovsund@177
  1605
            if ((Math.abs(blockEnd - endOffset) < 150) && (checkSameLine(doc, blockEnd, endOffset))) {
chrislovsund@177
  1606
                removeBlock(block, plsqlBlocks);
chrislovsund@177
  1607
                blockIsFound = true;
chrislovsund@177
  1608
                //assumption on max length of a package/procedure/function first line
chrislovsund@177
  1609
            } else if ((Math.abs(blockStart - startOffset) < 150) && (checkSameLine(doc, blockStart, startOffset))) {
chrislovsund@177
  1610
                removeBlock(block, plsqlBlocks);
chrislovsund@177
  1611
                blockIsFound = true;
chrislovsund@177
  1612
            } else if ((blockEnd < endOffset)
chrislovsund@177
  1613
                    && (blockStart > startOffset)) { //blocks which are enclosed by the affected area
chrislovsund@177
  1614
                removeBlock(block, plsqlBlocks);
chrislovsund@177
  1615
                blockIsFound = true;
chrislovsund@177
  1616
            } else if ((blockEnd > endOffset) && (blockStart < startOffset)
chrislovsund@177
  1617
                    && (block.getType() != PlsqlBlockType.PACKAGE && block.getType() != PlsqlBlockType.PACKAGE_BODY)) {
chrislovsund@177
  1618
                //affected area included in the block we need to remove the block.
chrislovsund@177
  1619
                //Idealy we should remove all types, but concerning on the performance did this
chrislovsund@177
  1620
                //comment might be removed here
chrislovsund@177
  1621
                removeBlock(block, plsqlBlocks);
chrislovsund@177
  1622
                blockIsFound = true;
chrislovsund@177
  1623
            } else {
chrislovsund@177
  1624
                boolean isFound = removeBlocksWithin(doc, block.getChildBlocks(), startOffset, endOffset);
chrislovsund@177
  1625
                if (!isFound) {
chrislovsund@177
  1626
                    if ((blockStart >= startOffset)
chrislovsund@177
  1627
                            && (blockStart <= endOffset)
chrislovsund@177
  1628
                            && (blockEnd >= endOffset)) {//first part of the block enclosed
chrislovsund@177
  1629
                        removeBlock(block, plsqlBlocks);
chrislovsund@177
  1630
                        blockIsFound = true;
chrislovsund@177
  1631
                    } else if ((blockEnd <= endOffset)
chrislovsund@177
  1632
                            && (blockEnd >= startOffset)
chrislovsund@177
  1633
                            && (blockStart <= startOffset)) {//end part of the block enclosed
chrislovsund@177
  1634
                        removeBlock(block, plsqlBlocks);
chrislovsund@177
  1635
                        blockIsFound = true;
chrislovsund@177
  1636
                    } else if ((blockEnd < endOffset)
chrislovsund@177
  1637
                            && (blockStart > startOffset)) { //blocks which are enclosed by the affected area
chrislovsund@177
  1638
                        removeBlock(block, plsqlBlocks);
chrislovsund@177
  1639
                        blockIsFound = true;
chrislovsund@177
  1640
                    } else if ((blockEnd > endOffset) && (blockStart < startOffset)
chrislovsund@177
  1641
                            && (block.getType() != PlsqlBlockType.PACKAGE && block.getType() != PlsqlBlockType.PACKAGE_BODY)) {
chrislovsund@177
  1642
                        //affected area included in the block we need to remove the block.
chrislovsund@177
  1643
                        //Idealy we should remove all types, but concerning on the performance did this
chrislovsund@177
  1644
                        //comment might be removed here
chrislovsund@177
  1645
                        removeBlock(block, plsqlBlocks);
chrislovsund@177
  1646
                        blockIsFound = true;
chrislovsund@177
  1647
                    }
chrislovsund@177
  1648
                }
chrislovsund@177
  1649
            }
chrislovsund@177
  1650
        }
chrislovsund@177
  1651
        return blockIsFound;
chrislovsund@177
  1652
    }
chrislovsund@177
  1653
chrislovsund@177
  1654
    /**
chrislovsund@177
  1655
     * Remove custom fold blocks that are there within the parse area
chrislovsund@362
  1656
     *
chrislovsund@177
  1657
     * @param customFoldBlocks
chrislovsund@177
  1658
     * @param startParse
chrislovsund@177
  1659
     * @param endParse
chrislovsund@177
  1660
     */
chrislovsund@177
  1661
    private void removeCustomBlocks(List<PlsqlBlock> customFoldBlocks, int startParse, int endParse) {
chrislovsund@177
  1662
        for (int i = customFoldBlocks.size() - 1; i >= 0; i--) {
chrislovsund@177
  1663
            PlsqlBlock block = customFoldBlocks.get(i);
chrislovsund@177
  1664
            if ((block.getStartOffset() >= startParse)
chrislovsund@177
  1665
                    && (block.getEndOffset() <= endParse)) {
chrislovsund@177
  1666
                customFoldBlocks.remove(i);
chrislovsund@177
  1667
            } else if ((block.getEndOffset() <= endParse)
chrislovsund@177
  1668
                    && (block.getEndOffset() >= startParse)
chrislovsund@177
  1669
                    && (block.getStartOffset() <= startParse)) {
chrislovsund@177
  1670
                customFoldBlocks.remove(i);
chrislovsund@177
  1671
            } else if ((block.getStartOffset() >= startParse)
chrislovsund@177
  1672
                    && (block.getStartOffset() <= endParse)
chrislovsund@177
  1673
                    && (block.getEndOffset() >= endParse)) {
chrislovsund@177
  1674
                customFoldBlocks.remove(i);
chrislovsund@177
  1675
            }
chrislovsund@177
  1676
        }
chrislovsund@177
  1677
    }
chrislovsund@177
  1678
chrislovsund@177
  1679
    /**
chrislovsund@177
  1680
     * If given block exists in the hier delete
chrislovsund@362
  1681
     *
chrislovsund@177
  1682
     * @param child
chrislovsund@177
  1683
     * @param parentBlocks
chrislovsund@177
  1684
     */
chrislovsund@177
  1685
    private void removeFromParent(PlsqlBlock child, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
  1686
        for (int i = 0; i < parentBlocks.size(); i++) {
chrislovsund@177
  1687
            PlsqlBlock tmp = parentBlocks.get(i);
chrislovsund@177
  1688
            if ((tmp.getEndOffset() == child.getEndOffset())
chrislovsund@177
  1689
                    && (tmp.getStartOffset() == child.getStartOffset())) {
chrislovsund@177
  1690
                parentBlocks.remove(tmp);
chrislovsund@177
  1691
                break;
chrislovsund@177
  1692
            }
chrislovsund@177
  1693
        }
chrislovsund@177
  1694
    }
chrislovsund@177
  1695
chrislovsund@177
  1696
    private boolean sqlPlusLine(TokenSequence<PlsqlTokenId> ts) {
chrislovsund@177
  1697
        int offset = ts.offset();
chrislovsund@177
  1698
        boolean isSqlPlus = false;
chrislovsund@177
  1699
        Token<PlsqlTokenId> token = null;
chrislovsund@177
  1700
        Token<PlsqlTokenId> tokenPre = null;
chrislovsund@177
  1701
        while (ts.movePrevious()) {
chrislovsund@177
  1702
            token = ts.token();
chrislovsund@177
  1703
            if (token.id() == PlsqlTokenId.WHITESPACE && token.toString().contains("\n")) {
chrislovsund@177
  1704
                if (tokenPre != null && tokenPre.id() == PlsqlTokenId.SQL_PLUS) {
chrislovsund@177
  1705
                    isSqlPlus = true;
chrislovsund@177
  1706
                }
chrislovsund@177
  1707
                break;
chrislovsund@177
  1708
            }
chrislovsund@177
  1709
chrislovsund@177
  1710
            if (token.id() != PlsqlTokenId.WHITESPACE) {
chrislovsund@177
  1711
                tokenPre = token;
chrislovsund@177
  1712
            }
chrislovsund@177
  1713
        }
chrislovsund@177
  1714
chrislovsund@177
  1715
        if (tokenPre != null && tokenPre.id() == PlsqlTokenId.SQL_PLUS) {
chrislovsund@177
  1716
            isSqlPlus = true;
chrislovsund@177
  1717
        }
chrislovsund@177
  1718
chrislovsund@177
  1719
        ts.move(offset);
chrislovsund@177
  1720
        ts.moveNext();
chrislovsund@177
  1721
        return isSqlPlus;
chrislovsund@177
  1722
    }
chrislovsund@177
  1723
chrislovsund@177
  1724
    /**
chrislovsund@177
  1725
     * Update block hierarchy based on the document event and the action
chrislovsund@177
  1726
     */
chrislovsund@177
  1727
    private synchronized void updateBlocks(Document doc, List<EventProperties> docList) {
chrislovsund@362
  1728
        LOG.log(Level.FINE, "updateBlocks", new Object[]{doc, docList});
chrislovsund@177
  1729
        clear();
chrislovsund@177
  1730
        try {
chrislovsund@177
  1731
            ((AbstractDocument) doc).readLock();
chrislovsund@177
  1732
chrislovsund@177
  1733
            docStartOffset = doc.getStartPosition().getOffset();
chrislovsund@177
  1734
            docEndOffset = doc.getEndPosition().getOffset();
chrislovsund@177
  1735
chrislovsund@177
  1736
            EventProperties event = docList.get(0);
chrislovsund@177
  1737
            //Area to be re parsed
chrislovsund@177
  1738
            startParse = event.offset;
chrislovsund@177
  1739
            endParse = event.offset + event.length;
chrislovsund@177
  1740
            if (event.mode == DocumentEvent.EventType.REMOVE) {
chrislovsund@177
  1741
                endParse = startParse;
chrislovsund@177
  1742
            }
chrislovsund@177
  1743
chrislovsund@177
  1744
            for (int x = 0; x < docList.size(); x++) {
chrislovsund@177
  1745
                event = docList.get(x);
chrislovsund@362
  1746
                LOG.log(Level.FINE, "event={0}, ", new Object[]{event});
chrislovsund@177
  1747
                int offset = event.offset;
chrislovsund@177
  1748
                int length = event.length;
chrislovsund@177
  1749
                DocumentEvent.EventType action = event.mode;
chrislovsund@177
  1750
chrislovsund@177
  1751
                //get the affected area
chrislovsund@177
  1752
                int startOffset = offset;
chrislovsund@177
  1753
                int endOffset = startOffset + length;
chrislovsund@177
  1754
                if (action == DocumentEvent.EventType.REMOVE) {
chrislovsund@177
  1755
                    endOffset = startOffset;
chrislovsund@177
  1756
                }
chrislovsund@177
  1757
chrislovsund@177
  1758
                //If action is remove, remove code folds in the affected area and repass them
chrislovsund@177
  1759
                if (action == DocumentEvent.EventType.REMOVE || action == DocumentEvent.EventType.INSERT) {
chrislovsund@177
  1760
                    if (action == DocumentEvent.EventType.REMOVE) {
chrislovsund@177
  1761
                        //Rearrange the offsets of the blocks below the area
chrislovsund@177
  1762
                        removeEnclosedBlocks(doc, blockHierarchy, startOffset, startOffset + length);
chrislovsund@177
  1763
                        changeOffSet(blockHierarchy, startOffset, -length, true, false);
chrislovsund@177
  1764
                        changeOffSet(customFoldBlocks, startOffset, -length, true, false);
chrislovsund@177
  1765
                        changeOffSet(toBeRemoved, startOffset, -length, false, true);
chrislovsund@177
  1766
                        changedLength = changedLength - length;
chrislovsund@177
  1767
                    } else if (action == DocumentEvent.EventType.INSERT) {
chrislovsund@177
  1768
                        //Rearrange the offsets of the blocks below the start of the area                  
chrislovsund@177
  1769
                        changeOffSet(blockHierarchy, startOffset, length, true, false);
chrislovsund@177
  1770
                        changeOffSet(customFoldBlocks, startOffset, length, true, false);
chrislovsund@177
  1771
                        changeOffSet(toBeRemoved, startOffset, length, false, true);
chrislovsund@177
  1772
                        changedLength = changedLength + length;
chrislovsund@177
  1773
                    }
chrislovsund@177
  1774
                    //adjust offsets according to the change
chrislovsund@177
  1775
                    if (startParse > startOffset) {
chrislovsund@177
  1776
                        startParse = startOffset;
chrislovsund@177
  1777
                    }
chrislovsund@177
  1778
                    if (endParse < endOffset) {
chrislovsund@177
  1779
                        endParse = endOffset;
chrislovsund@177
  1780
                    }
chrislovsund@177
  1781
chrislovsund@177
  1782
                    int count = blockHierarchy.size();
chrislovsund@177
  1783
                    removeBlocksWithin(doc, blockHierarchy, startOffset, endOffset);
chrislovsund@177
  1784
                    //If action removeimmediately before block and after block
chrislovsund@177
  1785
                    if (count == 0) {//If no blocks pass the whole root
chrislovsund@177
  1786
chrislovsund@177
  1787
                        startParse = docStartOffset;
chrislovsund@177
  1788
                        endParse = docEndOffset - 1;
chrislovsund@177
  1789
                    } else {
chrislovsund@177
  1790
                        if (startParse == startOffset) {//if start offset already adjusted no need to do again
chrislovsund@177
  1791
chrislovsund@177
  1792
                            PlsqlBlock block = null;
chrislovsund@177
  1793
                            block = getImmediateBefore(blockHierarchy, block, startOffset);
chrislovsund@177
  1794
                            PlsqlBlock parent = getParentBlock(blockHierarchy, startParse, endParse);
chrislovsund@177
  1795
chrislovsund@177
  1796
                            if ((parent != null) && (block != null)) {
chrislovsund@177
  1797
                                if (parent.getStartOffset() > block.getStartOffset()) {
chrislovsund@177
  1798
                                    int newStart = getSecondLineOfBlock(doc, parent); // we are not going to remove the parent here
chrislovsund@177
  1799
                                    if (newStart < startParse) {
chrislovsund@177
  1800
                                        startParse = newStart;
chrislovsund@177
  1801
                                    }
chrislovsund@177
  1802
                                } else {
chrislovsund@177
  1803
                                    removeBlock(block, parent.getChildBlocks());
chrislovsund@177
  1804
                                }
chrislovsund@177
  1805
                            } else {
chrislovsund@177
  1806
                                if (block != null) {
chrislovsund@177
  1807
                                    removeBlock(block, blockHierarchy);
chrislovsund@177
  1808
                                } else if (parent != null) { // we are not going to remove the parent here
chrislovsund@177
  1809
chrislovsund@177
  1810
                                    int newStart = getSecondLineOfBlock(doc, parent);
chrislovsund@177
  1811
                                    if (newStart < startParse) {
chrislovsund@177
  1812
                                        startParse = newStart;
chrislovsund@177
  1813
                                    }
chrislovsund@177
  1814
                                } else {
chrislovsund@177
  1815
                                    startParse = docStartOffset;
chrislovsund@177
  1816
                                }
chrislovsund@177
  1817
                            }
chrislovsund@177
  1818
                        }
chrislovsund@177
  1819
chrislovsund@177
  1820
                        if (endParse == endOffset) {//if end offset already adjusted no need to do again
chrislovsund@177
  1821
chrislovsund@177
  1822
                            PlsqlBlock block = null;
chrislovsund@177
  1823
                            block = getImmediateAfter(blockHierarchy, block, endOffset);
chrislovsund@177
  1824
                            PlsqlBlock parent = getParentBlock(blockHierarchy, startParse, endParse);
chrislovsund@177
  1825
chrislovsund@177
  1826
                            if ((parent != null) && (block != null)) {
chrislovsund@177
  1827
                                if (parent.getEndOffset() < block.getEndOffset()) {
chrislovsund@177
  1828
                                    int newEnd = getPreLineOfBlockEnd(doc, parent); // we are not going to remove the parent here
chrislovsund@177
  1829
                                    if (newEnd > endParse) {
chrislovsund@177
  1830
                                        endParse = newEnd;
chrislovsund@177
  1831
                                    }
chrislovsund@177
  1832
                                } else {
chrislovsund@177
  1833
                                    removeBlock(block, parent.getChildBlocks());
chrislovsund@177
  1834
                                }
chrislovsund@177
  1835
                            } else {
chrislovsund@177
  1836
                                if (block != null) {
chrislovsund@177
  1837
                                    removeBlock(block, blockHierarchy);
chrislovsund@177
  1838
                                } else if (parent != null) { // we are not going to remove the parent here
chrislovsund@177
  1839
chrislovsund@177
  1840
                                    int newEnd = getPreLineOfBlockEnd(doc, parent);
chrislovsund@177
  1841
                                    if (newEnd > endParse) {
chrislovsund@177
  1842
                                        endParse = newEnd;
chrislovsund@177
  1843
                                    }
chrislovsund@177
  1844
                                } else {
chrislovsund@177
  1845
                                    endParse = docEndOffset - 1;
chrislovsund@177
  1846
                                }
chrislovsund@177
  1847
                            }
chrislovsund@177
  1848
                        }
chrislovsund@177
  1849
chrislovsund@177
  1850
                        //Remove custom fold blocks that are there within the parse area
chrislovsund@177
  1851
                        removeCustomBlocks(customFoldBlocks, startParse, endParse);
chrislovsund@177
  1852
chrislovsund@177
  1853
                        //When files are deleted and written after opening once following can happen
chrislovsund@177
  1854
                        if ((endParse < 0) || (endParse > docEndOffset - 1)) {
chrislovsund@177
  1855
                            endParse = docEndOffset - 1;
chrislovsund@177
  1856
                        }
chrislovsund@177
  1857
chrislovsund@177
  1858
                        if (startParse < 0) {
chrislovsund@177
  1859
                            startParse = docStartOffset;
chrislovsund@177
  1860
                        }
chrislovsund@177
  1861
chrislovsund@177
  1862
                        if (startParse > docEndOffset - 1) {
chrislovsund@177
  1863
                            startParse = docEndOffset - 1;
chrislovsund@177
  1864
                        }
chrislovsund@177
  1865
                    }
chrislovsund@177
  1866
                } else { //UPDATE pass again
chrislovsund@177
  1867
chrislovsund@177
  1868
                    startParse = docStartOffset;
chrislovsund@177
  1869
                    endParse = docEndOffset - 1;
chrislovsund@177
  1870
chrislovsund@177
  1871
                    //clean block hierarchy
chrislovsund@177
  1872
                    blockHierarchy.clear();
chrislovsund@177
  1873
                    customFoldBlocks.clear();
chrislovsund@177
  1874
chrislovsund@177
  1875
                    //we are going for a reparse, remove all the events for this doc
chrislovsund@177
  1876
                    docList.clear();
chrislovsund@177
  1877
                    break;
chrislovsund@177
  1878
                }
chrislovsund@177
  1879
            }
chrislovsund@177
  1880
chrislovsund@177
  1881
            if (startParse >= endParse) //Can happen in removes
chrislovsund@177
  1882
            {
chrislovsund@177
  1883
                return;
chrislovsund@177
  1884
            }
chrislovsund@177
  1885
chrislovsund@177
  1886
            //Check whether defines are changed from the affected area
chrislovsund@177
  1887
            checkAffected(doc, startParse, endParse);
chrislovsund@177
  1888
chrislovsund@177
  1889
            if (isDefineChanged) {
chrislovsund@177
  1890
                getAliases(doc);
chrislovsund@177
  1891
            }
chrislovsund@177
  1892
chrislovsund@177
  1893
            //pass affected section again
chrislovsund@177
  1894
            generateBlocks(doc);
chrislovsund@177
  1895
chrislovsund@177
  1896
        } catch (Exception e) {
chrislovsund@177
  1897
            ErrorManager.getDefault().notify(e);
chrislovsund@177
  1898
        } finally {
chrislovsund@177
  1899
            ((AbstractDocument) doc).readUnlock();
chrislovsund@177
  1900
        }
chrislovsund@177
  1901
    }
chrislovsund@177
  1902
chrislovsund@177
  1903
    /**
chrislovsund@177
  1904
     * Get block which is immediately before the given offset
chrislovsund@362
  1905
     *
chrislovsund@177
  1906
     * @param blocks
chrislovsund@177
  1907
     * @param block
chrislovsund@177
  1908
     * @param offset
chrislovsund@177
  1909
     * @return
chrislovsund@177
  1910
     */
chrislovsund@177
  1911
    private PlsqlBlock getImmediateBefore(List blocks, PlsqlBlock block, int offset) {
chrislovsund@177
  1912
        int count = blocks.size();
chrislovsund@177
  1913
chrislovsund@177
  1914
        for (int i = 0; i < count; i++) {
chrislovsund@177
  1915
            PlsqlBlock temp = (PlsqlBlock) blocks.get(i);
chrislovsund@177
  1916
            //check from children
chrislovsund@177
  1917
            PlsqlBlock child = getImmediateBefore(temp.getChildBlocks(), block, offset);
jrechtacek@0
  1918
            if (child != null) {
chrislovsund@177
  1919
                block = child;
jrechtacek@0
  1920
            }
jrechtacek@0
  1921
chrislovsund@177
  1922
            if ((temp.getEndOffset() < offset)
chrislovsund@177
  1923
                    && ((block == null) || (block.getEndOffset() < temp.getEndOffset()))) {
chrislovsund@177
  1924
                block = temp;
jrechtacek@0
  1925
            }
chrislovsund@177
  1926
        }
chrislovsund@177
  1927
chrislovsund@177
  1928
        return block;
chrislovsund@177
  1929
    }
chrislovsund@177
  1930
chrislovsund@177
  1931
    /**
chrislovsund@177
  1932
     * Get fold which is immediately after the given offset
chrislovsund@362
  1933
     *
chrislovsund@177
  1934
     * @param blocks
chrislovsund@177
  1935
     * @param block
chrislovsund@177
  1936
     * @param offset
chrislovsund@177
  1937
     * @return
chrislovsund@177
  1938
     */
chrislovsund@177
  1939
    private PlsqlBlock getImmediateAfter(List<PlsqlBlock> blocks, PlsqlBlock block, int offset) {
chrislovsund@177
  1940
        int count = blocks.size();
chrislovsund@177
  1941
chrislovsund@177
  1942
        for (int i = 0; i < count; i++) {
chrislovsund@177
  1943
            PlsqlBlock temp = blocks.get(i);
chrislovsund@177
  1944
            //check from children
chrislovsund@177
  1945
            PlsqlBlock child = getImmediateAfter(temp.getChildBlocks(), block, offset);
chrislovsund@177
  1946
            if (child != null) {
chrislovsund@177
  1947
                block = child;
jrechtacek@0
  1948
            }
chrislovsund@177
  1949
chrislovsund@177
  1950
            if ((temp.getStartOffset() > offset)
chrislovsund@177
  1951
                    && ((block == null) || (block.getStartOffset() > temp.getStartOffset()))) {
chrislovsund@177
  1952
                block = temp;
jrechtacek@0
  1953
            }
chrislovsund@177
  1954
        }
chrislovsund@177
  1955
chrislovsund@177
  1956
        return block;
chrislovsund@177
  1957
    }
chrislovsund@177
  1958
chrislovsund@177
  1959
    /**
chrislovsund@177
  1960
     * Method that will generate blocks of the given offset range
chrislovsund@362
  1961
     *
chrislovsund@177
  1962
     * @param startOffset
chrislovsund@177
  1963
     * @param endOffset
chrislovsund@177
  1964
     */
chrislovsund@177
  1965
    private synchronized void generateBlocks(Document doc) {
chrislovsund@177
  1966
        List<PlsqlBlock> immediateBlockHier;
chrislovsund@177
  1967
        tokenHierarchy = TokenHierarchy.get(doc);
chrislovsund@177
  1968
        @SuppressWarnings("unchecked")
chrislovsund@177
  1969
        TokenSequence<PlsqlTokenId> ts = tokenHierarchy.tokenSequence(PlsqlTokenId.language());
chrislovsund@362
  1970
        if (ts == null) {
chrislovsund@362
  1971
            return;
chrislovsund@362
  1972
        }
chrislovsund@177
  1973
chrislovsund@177
  1974
        PlsqlBlock parent = getParentBlock(blockHierarchy, startParse, endParse);
chrislovsund@177
  1975
        if (parent != null) {
chrislovsund@177
  1976
            immediateBlockHier = parent.getChildBlocks();
chrislovsund@177
  1977
        } else {
chrislovsund@177
  1978
            immediateBlockHier = blockHierarchy;
chrislovsund@177
  1979
        }
chrislovsund@177
  1980
chrislovsund@362
  1981
        LOG.log(Level.FINE, "generateBlocks, doc.getLength()={0}, ts.tokenCount()={1}",
chrislovsund@362
  1982
                new Object[]{doc.getLength(), ts.tokenCount()});
chrislovsund@362
  1983
        //move offset
chrislovsund@362
  1984
        ts.move(startParse);
chrislovsund@362
  1985
        Token<PlsqlTokenId> tempToken;
chrislovsund@362
  1986
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@362
  1987
        Token<PlsqlTokenId> customEndToken = null;
chrislovsund@362
  1988
chrislovsund@362
  1989
        //Go through all the available tokens
chrislovsund@362
  1990
        while (ts.moveNext()) {
chrislovsund@362
  1991
            tempToken = ts.token();
chrislovsund@362
  1992
            PlsqlTokenId tokenID = tempToken.id();
chrislovsund@362
  1993
            String image = tempToken.text().toString();
chrislovsund@362
  1994
chrislovsund@362
  1995
            LOG.log(Level.FINE, "tempToken.id()={0}, tempToken.text()={1}",
chrislovsund@362
  1996
                    new Object[]{tempToken.id(), tempToken.text()});
chrislovsund@362
  1997
chrislovsund@362
  1998
            //Check end offset and break (exception for colun which will mark end of some blocks)
chrislovsund@362
  1999
            if ((!image.equals(";")) && (tempToken.offset(tokenHierarchy) > endParse)) {
chrislovsund@362
  2000
                break;
chrislovsund@362
  2001
            }
chrislovsund@362
  2002
chrislovsund@362
  2003
            if (tokenID == PlsqlTokenId.KEYWORD) {
chrislovsund@362
  2004
                if (image.equalsIgnoreCase("VIEW")) {
chrislovsund@362
  2005
                    int offset = ts.offset();
chrislovsund@362
  2006
                    PlsqlBlock block = checkView(tempToken, ts, immediateBlockHier);
chrislovsund@362
  2007
                    if (block == null) {
chrislovsund@362
  2008
                        //pass from the immediate next token to get inner blocks
chrislovsund@362
  2009
                        ts.move(offset);
chrislovsund@362
  2010
                        ts.moveNext();
chrislovsund@362
  2011
                    } else {
chrislovsund@362
  2012
                        checkAndAddNew(block, parent, immediateBlockHier);
chrislovsund@362
  2013
                    }
chrislovsund@362
  2014
                } else if (image.equalsIgnoreCase("FUNCTION")) {
chrislovsund@362
  2015
                    int offset = ts.offset();
chrislovsund@362
  2016
                    PlsqlBlock block = checkMethod(tempToken, ts, PlsqlBlockType.FUNCTION_IMPL, immediateBlockHier);
chrislovsund@362
  2017
                    if (block == null) {
chrislovsund@362
  2018
                        //pass from the immediate next token to get inner blocks
chrislovsund@362
  2019
                        ts.move(offset);
chrislovsund@362
  2020
                        ts.moveNext();
chrislovsund@362
  2021
                    } else {
chrislovsund@362
  2022
                        checkAndAddNew(block, parent, immediateBlockHier);
chrislovsund@362
  2023
                    }
chrislovsund@362
  2024
                } else if (image.equalsIgnoreCase("PROCEDURE")) {
chrislovsund@362
  2025
                    int offset = ts.offset();
chrislovsund@362
  2026
                    PlsqlBlock block = checkMethod(tempToken, ts, PlsqlBlockType.PROCEDURE_IMPL, immediateBlockHier);
chrislovsund@362
  2027
                    if (block == null) {
chrislovsund@362
  2028
                        //pass from the immediate next token to get inner blocks
chrislovsund@362
  2029
                        ts.move(offset);
chrislovsund@362
  2030
                        ts.moveNext();
chrislovsund@362
  2031
                    } else {
chrislovsund@362
  2032
                        checkAndAddNew(block, parent, immediateBlockHier);
chrislovsund@362
  2033
                    }
chrislovsund@362
  2034
                } else if (image.equalsIgnoreCase("PACKAGE")) {
chrislovsund@362
  2035
                    int offset = ts.offset();
chrislovsund@362
  2036
                    PlsqlBlock block = checkPackage(tempToken, ts, immediateBlockHier);
chrislovsund@362
  2037
                    if (block == null) {
chrislovsund@362
  2038
                        //pass from the immediate next token to get inner blocks
chrislovsund@362
  2039
                        ts.move(offset);
chrislovsund@362
  2040
                        ts.moveNext();
chrislovsund@362
  2041
                    } else {
chrislovsund@362
  2042
                        checkAndAddNew(block, parent, immediateBlockHier);
chrislovsund@362
  2043
                    }
chrislovsund@362
  2044
                } else if (image.equalsIgnoreCase("CURSOR")) {
chrislovsund@362
  2045
                    int offset = ts.offset();
chrislovsund@362
  2046
                    PlsqlBlock block = checkCursor(tempToken, ts, immediateBlockHier);
chrislovsund@362
  2047
                    if (block == null) {
chrislovsund@362
  2048
                        //pass from the immediate next token to get inner blocks
chrislovsund@362
  2049
                        ts.move(offset);
chrislovsund@362
  2050
                        ts.moveNext();
chrislovsund@362
  2051
                    } else {
chrislovsund@362
  2052
                        checkAndAddNew(block, parent, immediateBlockHier);
chrislovsund@362
  2053
                    }
chrislovsund@362
  2054
                } else if (image.equalsIgnoreCase("TRIGGER")) {
chrislovsund@362
  2055
                    int offset = ts.offset();
chrislovsund@362
  2056
                    PlsqlBlock block = checkTrigger(tempToken, ts, immediateBlockHier);
chrislovsund@362
  2057
                    if (block == null) {
chrislovsund@362
  2058
                        //pass from the immediate next token to get inner blocks
chrislovsund@362
  2059
                        ts.move(offset);
chrislovsund@362
  2060
                        ts.moveNext();
chrislovsund@362
  2061
                    } else {
chrislovsund@362
  2062
                        checkAndAddNew(block, parent, immediateBlockHier);
chrislovsund@362
  2063
                    }
chrislovsund@362
  2064
                } else if (image.equalsIgnoreCase("COMMENT")) {
chrislovsund@362
  2065
                    int offset = ts.offset();
chrislovsund@362
  2066
                    PlsqlBlock block = checkTblColComment(tempToken, ts, immediateBlockHier);
chrislovsund@362
  2067
                    if (block == null) {
chrislovsund@362
  2068
                        //pass from the immediate next token to get inner blocks
chrislovsund@362
  2069
                        ts.move(offset);
chrislovsund@362
  2070
                        ts.moveNext();
chrislovsund@362
  2071
                    } else {
chrislovsund@362
  2072
                        checkAndAddNew(block, parent, immediateBlockHier);
chrislovsund@362
  2073
                    }
chrislovsund@362
  2074
                } else if (image.equalsIgnoreCase("DECLARE")) {
chrislovsund@362
  2075
                    PlsqlBlock block = checkDeclareBlock(tempToken, ts, immediateBlockHier);
chrislovsund@362
  2076
                    if (block != null) {//If inner check seems to have failed need to continue this one
chrislovsund@362
  2077
                        checkAndAddNew(block, parent, immediateBlockHier);
chrislovsund@362
  2078
                    }
chrislovsund@362
  2079
                } else if (image.equalsIgnoreCase("BEGIN")) {
chrislovsund@362
  2080
                    if (!isDeclare(ts, immediateBlockHier)) {//We need to check whether the declare is isolated by a CURSOR block
chrislovsund@362
  2081
chrislovsund@177
  2082
                        int offset = ts.offset();
chrislovsund@362
  2083
                        PlsqlBlock block = checkBeginBlock(tempToken, ts, immediateBlockHier);
chrislovsund@362
  2084
                        if (block == null) {//If inner check seems to have failed need to continue this one
chrislovsund@362
  2085
chrislovsund@177
  2086
                            ts.move(offset);
chrislovsund@177
  2087
                            ts.moveNext();
jrechtacek@0
  2088
                        } else {
chrislovsund@177
  2089
                            checkAndAddNew(block, parent, immediateBlockHier);
jrechtacek@0
  2090
                        }
chrislovsund@362
  2091
                    }
chrislovsund@362
  2092
                } else if (image.equalsIgnoreCase("IF")
chrislovsund@362
  2093
                        || image.equalsIgnoreCase("ELSIF")) {
chrislovsund@362
  2094
                    if (!isNotBlockStart(tempToken, ts)) {
chrislovsund@362
  2095
                        int offset = tempToken.offset(tokenHierarchy);
chrislovsund@362
  2096
                        List children = checkIfBlock(tempToken, ts, immediateBlockHier);
chrislovsund@362
  2097
                        if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@362
  2098
chrislovsund@177
  2099
                            ts.move(offset);
chrislovsund@177
  2100
                            ts.moveNext();
jrechtacek@0
  2101
                        } else {
chrislovsund@362
  2102
                            for (int i = 0; i < children.size(); i++) {
chrislovsund@362
  2103
                                PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@362
  2104
                                checkAndAddNew(child, parent, immediateBlockHier);
chrislovsund@362
  2105
                            }
jrechtacek@0
  2106
                        }
chrislovsund@362
  2107
                    }
chrislovsund@362
  2108
                } else if (image.equalsIgnoreCase("ELSE")) {
chrislovsund@362
  2109
                    if (!isNotBlockStart(tempToken, ts)) {
chrislovsund@362
  2110
                        int offset = tempToken.offset(tokenHierarchy);
chrislovsund@362
  2111
                        List children = checkIfBlock(tempToken, ts, immediateBlockHier);
chrislovsund@362
  2112
                        if (children == null || children.isEmpty()) {
chrislovsund@362
  2113
                            children = checkCaseBlock(tempToken, ts, immediateBlockHier, false);
chrislovsund@362
  2114
                        }
chrislovsund@362
  2115
chrislovsund@362
  2116
                        if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@362
  2117
chrislovsund@177
  2118
                            ts.move(offset);
chrislovsund@177
  2119
                            ts.moveNext();
jrechtacek@0
  2120
                        } else {
chrislovsund@362
  2121
                            for (int i = 0; i < children.size(); i++) {
chrislovsund@362
  2122
                                PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@362
  2123
                                checkAndAddNew(child, parent, immediateBlockHier);
chrislovsund@362
  2124
                            }
jrechtacek@0
  2125
                        }
chrislovsund@362
  2126
                    }
chrislovsund@362
  2127
                } else if (image.equalsIgnoreCase("CASE")
chrislovsund@362
  2128
                        || image.equalsIgnoreCase("WHEN")) {
chrislovsund@362
  2129
                    if (!isNotBlockStart(tempToken, ts)) {
chrislovsund@362
  2130
                        int offset = tempToken.offset(tokenHierarchy);
chrislovsund@362
  2131
                        List children = checkCaseBlock(tempToken, ts, immediateBlockHier, false);
chrislovsund@362
  2132
                        if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@362
  2133
chrislovsund@177
  2134
                            ts.move(offset);
chrislovsund@177
  2135
                            ts.moveNext();
jrechtacek@0
  2136
                        } else {
chrislovsund@362
  2137
                            for (int i = 0; i < children.size(); i++) {
chrislovsund@362
  2138
                                PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@362
  2139
                                checkAndAddNew(child, parent, immediateBlockHier);
chrislovsund@177
  2140
                            }
chrislovsund@177
  2141
                        }
chrislovsund@362
  2142
                    }
chrislovsund@362
  2143
                } else if (image.equalsIgnoreCase("LOOP")
chrislovsund@362
  2144
                        || image.equalsIgnoreCase("WHILE")
chrislovsund@362
  2145
                        || image.equalsIgnoreCase("FOR")) {
chrislovsund@362
  2146
                    if (!isNotBlockStart(tempToken, ts)) {
chrislovsund@362
  2147
                        int offset = tempToken.offset(tokenHierarchy);
chrislovsund@362
  2148
                        if (!unsuccessBlocks.contains(offset)) {
chrislovsund@362
  2149
                            PlsqlBlock child = checkLoopBlock(tempToken, ts, immediateBlockHier);
chrislovsund@177
  2150
                            if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@362
  2151
                                unsuccessBlocks.add(offset);
chrislovsund@177
  2152
                                ts.move(offset);
chrislovsund@177
  2153
                                ts.moveNext();
chrislovsund@177
  2154
                            } else {
chrislovsund@177
  2155
                                checkAndAddNew(child, parent, immediateBlockHier);
chrislovsund@177
  2156
                            }
chrislovsund@177
  2157
                        }
chrislovsund@177
  2158
                    }
chrislovsund@362
  2159
                } else if (image.equalsIgnoreCase("TABLE")
chrislovsund@362
  2160
                        || image.equalsIgnoreCase("INDEX")
chrislovsund@362
  2161
                        || image.equalsIgnoreCase("SELECT")
chrislovsund@362
  2162
                        || image.equalsIgnoreCase("UPDATE")
chrislovsund@362
  2163
                        || image.equalsIgnoreCase("DELETE")
chrislovsund@362
  2164
                        || image.equalsIgnoreCase("INSERT")
chrislovsund@362
  2165
                        || image.equalsIgnoreCase("MERGE")
chrislovsund@362
  2166
                        || image.equalsIgnoreCase("DROP")
chrislovsund@362
  2167
                        || image.equalsIgnoreCase("SEQUENCE")) {
chrislovsund@362
  2168
                    if (!isNotBlockStart(tempToken, ts)) {
chrislovsund@362
  2169
                        int offset = tempToken.offset(tokenHierarchy);
chrislovsund@362
  2170
                        PlsqlBlock child = checkStatementBlock(tempToken, ts, immediateBlockHier);
chrislovsund@362
  2171
                        if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@362
  2172
subslk@405
  2173
//                            ts.move(offset);
subslk@405
  2174
//                            ts.moveNext();
chrislovsund@177
  2175
                        } else {
chrislovsund@362
  2176
                            checkAndAddNew(child, parent, immediateBlockHier);
jrechtacek@0
  2177
                        }
chrislovsund@177
  2178
                    }
chrislovsund@362
  2179
                }
chrislovsund@362
  2180
            } else if (tokenID == PlsqlTokenId.JAVA_SOUCE) {
chrislovsund@362
  2181
                int offset = ts.offset();
chrislovsund@362
  2182
                PlsqlBlock block = null;
chrislovsund@362
  2183
                block = checkJavaSource(tempToken, ts);
chrislovsund@362
  2184
                if (block == null) {
chrislovsund@362
  2185
                    //pass from the immediate next token to get inner blocks
chrislovsund@362
  2186
                    ts.move(offset);
chrislovsund@362
  2187
                    ts.moveNext();
chrislovsund@362
  2188
                } else {
chrislovsund@362
  2189
                    checkAndAddNew(block, parent, immediateBlockHier);
chrislovsund@362
  2190
                }
chrislovsund@362
  2191
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@362
  2192
                //only single comment line
chrislovsund@362
  2193
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@362
  2194
                    customStartToken = tempToken;
chrislovsund@362
  2195
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@362
  2196
                    if (customStartToken != null) {
chrislovsund@362
  2197
                        String name = customStartToken.text().toString();
chrislovsund@362
  2198
                        int index = name.toUpperCase(Locale.ENGLISH).indexOf("<FOLD>");
chrislovsund@362
  2199
                        name = name.substring(index + 7).trim();
chrislovsund@362
  2200
                        if (ts.moveNext()) {
chrislovsund@362
  2201
                            tempToken = ts.token();
chrislovsund@362
  2202
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@362
  2203
                                    tempToken.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@362
  2204
                            customFoldBlocks.add(custom);
chrislovsund@362
  2205
                        }
chrislovsund@362
  2206
                        customStartToken = null;
chrislovsund@362
  2207
                    } else {
chrislovsund@362
  2208
                        customEndToken = tempToken;
chrislovsund@362
  2209
                    }
chrislovsund@362
  2210
                } else {
chrislovsund@362
  2211
                    PlsqlBlock block = checkComment(tempToken, ts);
chrislovsund@177
  2212
                    if (block != null) {
chrislovsund@177
  2213
                        checkAndAddNew(block, parent, immediateBlockHier);
chrislovsund@177
  2214
                    }
chrislovsund@362
  2215
                }
chrislovsund@362
  2216
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@362
  2217
                int start = tempToken.offset(tokenHierarchy);
chrislovsund@362
  2218
                PlsqlBlock block = new PlsqlBlock(start,
chrislovsund@362
  2219
                        start + tempToken.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@362
  2220
                if (block != null) {
chrislovsund@362
  2221
                    checkAndAddNew(block, parent, immediateBlockHier);
chrislovsund@362
  2222
                }
chrislovsund@362
  2223
            } else if ((tokenID == PlsqlTokenId.OPERATOR) && (image.equals(";"))) {
chrislovsund@362
  2224
                PlsqlBlock block = checkEnd(tempToken, ts);
chrislovsund@362
  2225
                //check whether this is the parent can happen in a remove
chrislovsund@362
  2226
                if (block != null && (block.getType() != PlsqlBlockType.FUNCTION_IMPL && block.getType() != PlsqlBlockType.PROCEDURE_IMPL)) {
chrislovsund@362
  2227
                    if (!isEqual(parent, block)) {
chrislovsund@362
  2228
                        if ((block != null) && (checkExisting(block, immediateBlockHier) == false)) {
chrislovsund@362
  2229
                            addImmediateChildren(block, immediateBlockHier);
chrislovsund@362
  2230
                            immediateBlockHier.add(block);
chrislovsund@362
  2231
                            newBlocks.add(block);
chrislovsund@362
  2232
                            if (parent != null) {
chrislovsund@362
  2233
                                block.setParent(parent);
chrislovsund@177
  2234
                            }
jrechtacek@0
  2235
                        }
chrislovsund@177
  2236
                    }
chrislovsund@177
  2237
                }
jrechtacek@0
  2238
            }
chrislovsund@362
  2239
        }   //we have come to the end now, check whether we have unmatched custom tokens
chrislovsund@362
  2240
chrislovsund@362
  2241
        if (customEndToken != null) {
chrislovsund@362
  2242
            checkCustom(customEndToken, ts, immediateBlockHier, parent, "END");
chrislovsund@362
  2243
        } else if (customStartToken != null) {
chrislovsund@362
  2244
            checkCustom(customStartToken, ts, immediateBlockHier, parent, "START");
chrislovsund@177
  2245
        }
chrislovsund@177
  2246
    }
chrislovsund@177
  2247
chrislovsund@177
  2248
    private void checkAndAddNew(PlsqlBlock block, PlsqlBlock parent, List<PlsqlBlock> immediateBlockHier) {
chrislovsund@371
  2249
        LOG.log(Level.FINE, "checkAndAddNew, block.getName()={0}, block.getType()={1}", new Object[]{block.getName(), block.getType()});
chrislovsund@177
  2250
        if (checkExisting(block, immediateBlockHier) == false && !isEqual(parent, block)) {
chrislovsund@177
  2251
            immediateBlockHier.add(block);
chrislovsund@362
  2252
            LOG.log(Level.FINE, "newBlocks.add({0})", new Object[]{block.getName(), block.getType()});
chrislovsund@177
  2253
            newBlocks.add(block);
chrislovsund@177
  2254
            if (parent != null) {
chrislovsund@177
  2255
                block.setParent(parent);
chrislovsund@177
  2256
            }
chrislovsund@177
  2257
        }
chrislovsund@177
  2258
    }
chrislovsund@177
  2259
chrislovsund@177
  2260
    /**
chrislovsund@177
  2261
     * Check whether current ';' is the end of a function/procedure/view/package
chrislovsund@362
  2262
     *
chrislovsund@177
  2263
     * @param tempToken
chrislovsund@177
  2264
     * @param ts
chrislovsund@177
  2265
     */
chrislovsund@177
  2266
    private PlsqlBlock checkEnd(Token<PlsqlTokenId> endToken, TokenSequence<PlsqlTokenId> ts) {
chrislovsund@177
  2267
        Token<PlsqlTokenId> end = endToken; //means ';' here
chrislovsund@177
  2268
chrislovsund@177
  2269
        Token<PlsqlTokenId> begin = null;
chrislovsund@177
  2270
        String methodName = "";
chrislovsund@177
  2271
        int type = -1; //1 for FUNCTION/PROCEDURE/PACKAGE
chrislovsund@177
  2272
chrislovsund@177
  2273
        boolean moveBack = false;
chrislovsund@177
  2274
        PlsqlBlock block = null;
chrislovsund@177
  2275
        moveBack = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2276
        Token<PlsqlTokenId> tmp = ts.token();
chrislovsund@177
  2277
chrislovsund@177
  2278
        if (moveBack == false) {
jrechtacek@0
  2279
            ts.move(end.offset(tokenHierarchy));
jrechtacek@0
  2280
            ts.moveNext();
jrechtacek@0
  2281
            return block;
chrislovsund@177
  2282
        }
chrislovsund@177
  2283
chrislovsund@177
  2284
        //If this is a function/procedure end take the name
chrislovsund@177
  2285
        if ((tmp.id() == PlsqlTokenId.KEYWORD) && (tmp.text().toString().equalsIgnoreCase("END"))) {
chrislovsund@177
  2286
            type = 0;
chrislovsund@177
  2287
        } else if (tmp.id() == PlsqlTokenId.IDENTIFIER || tmp.id() == PlsqlTokenId.KEYWORD) {
chrislovsund@177
  2288
            methodName = tmp.text().toString();
chrislovsund@177
  2289
chrislovsund@177
  2290
            //Check whether this is an 'end <ide>;'
chrislovsund@177
  2291
            moveBack = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2292
            tmp = ts.token();
chrislovsund@177
  2293
chrislovsund@177
  2294
            if (moveBack == false) {
chrislovsund@177
  2295
                ts.move(end.offset(tokenHierarchy));
chrislovsund@177
  2296
                ts.moveNext();
chrislovsund@177
  2297
                return block;
chrislovsund@177
  2298
            }
chrislovsund@177
  2299
chrislovsund@177
  2300
            if ((tmp.id() == PlsqlTokenId.KEYWORD)
chrislovsund@177
  2301
                    && (tmp.text().toString().equalsIgnoreCase("END"))) {
chrislovsund@177
  2302
                type = 1;
chrislovsund@177
  2303
            }
chrislovsund@177
  2304
chrislovsund@177
  2305
        }
chrislovsund@177
  2306
chrislovsund@177
  2307
        if (type == 1) {
chrislovsund@177
  2308
            begin = checkMethodBegin(ts, methodName);
chrislovsund@177
  2309
        } else if (type == 0) {
chrislovsund@177
  2310
            begin = checkMethodBegin(ts);
chrislovsund@177
  2311
chrislovsund@177
  2312
            Token<PlsqlTokenId> nameToken = begin;
chrislovsund@177
  2313
            //get name
chrislovsund@177
  2314
            if (getNextNonWhitespace(ts, true)) {
chrislovsund@177
  2315
                nameToken = ts.token();
chrislovsund@177
  2316
                if (!nameToken.text().toString().equalsIgnoreCase("BODY")) {
chrislovsund@177
  2317
                    methodName = nameToken.text().toString();
chrislovsund@177
  2318
                } else {
chrislovsund@177
  2319
                    if (getNextNonWhitespace(ts, true)) {
chrislovsund@177
  2320
                        nameToken = ts.token();
chrislovsund@177
  2321
                        methodName = nameToken.text().toString();
chrislovsund@177
  2322
                    }
chrislovsund@177
  2323
                }
chrislovsund@177
  2324
            }
chrislovsund@177
  2325
        }
chrislovsund@177
  2326
chrislovsund@177
  2327
        //Cold block is found
chrislovsund@177
  2328
        if (begin != null) {
chrislovsund@177
  2329
            String image = begin.text().toString();
chrislovsund@177
  2330
            String alias = "";
chrislovsund@177
  2331
            if (methodName.indexOf('&') != -1) {
chrislovsund@177
  2332
                alias = methodName;
chrislovsund@177
  2333
            }
chrislovsund@177
  2334
chrislovsund@177
  2335
            methodName = getDefine(methodName);
chrislovsund@177
  2336
chrislovsund@177
  2337
            //Get the token after the end token
chrislovsund@177
  2338
            ts.move(end.offset(tokenHierarchy));
chrislovsund@177
  2339
            ts.moveNext();
chrislovsund@177
  2340
            ts.moveNext();
chrislovsund@177
  2341
chrislovsund@177
  2342
            if (image.equalsIgnoreCase("PROCEDURE")) {
chrislovsund@177
  2343
                block = new PlsqlBlock(begin.offset(tokenHierarchy), ts.offset(),
chrislovsund@177
  2344
                        methodName, alias, PlsqlBlockType.PROCEDURE_IMPL);
chrislovsund@177
  2345
                checkPrefix(begin.offset(tokenHierarchy), ts, block);
chrislovsund@177
  2346
            } else if (image.equalsIgnoreCase("PACKAGE")) {
chrislovsund@177
  2347
                //get next token & check
chrislovsund@177
  2348
                //find semicolon
chrislovsund@177
  2349
                int endPos = ts.offset();
chrislovsund@177
  2350
                ts.move(begin.offset(tokenHierarchy));
chrislovsund@177
  2351
                ts.moveNext();
chrislovsund@177
  2352
                boolean moveNext = false;
chrislovsund@177
  2353
                moveNext = getNextNonWhitespace(ts, true);
chrislovsund@177
  2354
                Token<PlsqlTokenId> next = ts.token();
chrislovsund@177
  2355
                PlsqlBlockType foldType = PlsqlBlockType.PACKAGE;
chrislovsund@177
  2356
                if ((moveNext != false) && (next.text().toString().equalsIgnoreCase("BODY"))) {
chrislovsund@177
  2357
                    foldType = PlsqlBlockType.PACKAGE_BODY;
chrislovsund@177
  2358
                }
chrislovsund@177
  2359
chrislovsund@177
  2360
                block = new PlsqlBlock(begin.offset(tokenHierarchy), endPos,
chrislovsund@177
  2361
                        methodName, alias, foldType);
chrislovsund@177
  2362
                checkPrefix(begin.offset(tokenHierarchy), ts, block);
jrechtacek@0
  2363
            } else {
chrislovsund@177
  2364
                block = new PlsqlBlock(begin.offset(tokenHierarchy), ts.offset(),
chrislovsund@177
  2365
                        methodName, alias, PlsqlBlockType.FUNCTION_IMPL);
chrislovsund@177
  2366
                checkPrefix(begin.offset(tokenHierarchy), ts, block);
jrechtacek@0
  2367
            }
chrislovsund@177
  2368
        }
chrislovsund@177
  2369
chrislovsund@177
  2370
        ts.move(end.offset(tokenHierarchy));
chrislovsund@177
  2371
        ts.moveNext();
chrislovsund@177
  2372
        return block;
chrislovsund@177
  2373
    }
chrislovsund@177
  2374
chrislovsund@177
  2375
    /**
chrislovsund@177
  2376
     * Check whether there is a function/procedure in this block
chrislovsund@362
  2377
     *
chrislovsund@177
  2378
     * @param ts
chrislovsund@177
  2379
     * @param methodName
chrislovsund@177
  2380
     * @return
chrislovsund@177
  2381
     */
chrislovsund@177
  2382
    private Token<PlsqlTokenId> checkMethodBegin(TokenSequence<PlsqlTokenId> ts, String methodName) {
chrislovsund@177
  2383
        Token<PlsqlTokenId> begin = null;
chrislovsund@177
  2384
        boolean moveBack = ts.movePrevious();
chrislovsund@177
  2385
        Token<PlsqlTokenId> tmp = ts.token();
chrislovsund@177
  2386
        int endCount = 0;
chrislovsund@177
  2387
chrislovsund@177
  2388
        while (moveBack) {
chrislovsund@177
  2389
            String image = tmp.text().toString();
chrislovsund@177
  2390
chrislovsund@177
  2391
            if (image.equalsIgnoreCase(methodName)) {
chrislovsund@177
  2392
                //Go to previous word
chrislovsund@177
  2393
                boolean move = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2394
                Token<PlsqlTokenId> token = ts.token();
chrislovsund@177
  2395
chrislovsund@177
  2396
                if ((move != false) && (token.id() == PlsqlTokenId.KEYWORD)) {
chrislovsund@177
  2397
                    if ((token.text().toString().equalsIgnoreCase("FUNCTION"))
chrislovsund@177
  2398
                            || (token.text().toString().equalsIgnoreCase("PROCEDURE"))) {
chrislovsund@177
  2399
                        //if there were inner functions & procedures
chrislovsund@177
  2400
                        if (endCount != 0) {
chrislovsund@177
  2401
                            endCount--;
chrislovsund@177
  2402
                        } else {
chrislovsund@177
  2403
                            return token;
chrislovsund@177
  2404
                        }
chrislovsund@177
  2405
                    } else if (token.text().toString().equalsIgnoreCase("BODY")) {
chrislovsund@177
  2406
                        boolean pre = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2407
                        Token<PlsqlTokenId> previous = ts.token();
chrislovsund@177
  2408
                        if ((pre != false) && (previous.text().toString().equalsIgnoreCase("PACKAGE"))) {
chrislovsund@177
  2409
                            return previous;
chrislovsund@177
  2410
                        }
chrislovsund@177
  2411
chrislovsund@177
  2412
                    } else if (token.text().toString().equalsIgnoreCase("END")) {
chrislovsund@177
  2413
                        ++endCount;
chrislovsund@177
  2414
                    }
chrislovsund@177
  2415
                }
chrislovsund@177
  2416
            }
chrislovsund@177
  2417
            moveBack = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2418
            tmp = ts.token();
chrislovsund@177
  2419
        }
chrislovsund@177
  2420
chrislovsund@177
  2421
        return begin;
chrislovsund@177
  2422
    }
chrislovsund@177
  2423
chrislovsund@177
  2424
    /**
chrislovsund@362
  2425
     * Check whether there is a function/procedure in this block Method name is not there in the 'END;'
chrislovsund@362
  2426
     *
chrislovsund@177
  2427
     * @param ts
chrislovsund@177
  2428
     * @return
chrislovsund@177
  2429
     */
chrislovsund@177
  2430
    private Token<PlsqlTokenId> checkMethodBegin(TokenSequence<PlsqlTokenId> ts) {
chrislovsund@177
  2431
        Token<PlsqlTokenId> begin = null;
chrislovsund@177
  2432
        boolean moveBack = ts.movePrevious();
chrislovsund@177
  2433
        Token<PlsqlTokenId> tmp = ts.token();
chrislovsund@177
  2434
        int endCount = 0;
chrislovsund@177
  2435
chrislovsund@177
  2436
        while (moveBack) {
chrislovsund@177
  2437
            String image = tmp.text().toString();
chrislovsund@177
  2438
chrislovsund@177
  2439
            if (tmp.id() == PlsqlTokenId.KEYWORD) {
chrislovsund@177
  2440
                if ((image.equalsIgnoreCase("BEGIN"))) {
chrislovsund@177
  2441
                    endCount--;
chrislovsund@177
  2442
                } else if ((image.equalsIgnoreCase("END"))) {
chrislovsund@177
  2443
                    int off = ts.offset();
chrislovsund@177
  2444
                    if (getNextNonWhitespace(ts, true)) {
chrislovsund@177
  2445
                        tmp = ts.token();
chrislovsund@177
  2446
                    }
chrislovsund@177
  2447
chrislovsund@177
  2448
                    if ((tmp.text().toString().equals(";")) || (tmp.id() == PlsqlTokenId.IDENTIFIER)
chrislovsund@177
  2449
                            || (tmp.id() == PlsqlTokenId.KEYWORD && (!tmp.toString().equalsIgnoreCase("IF")
chrislovsund@177
  2450
                            && !tmp.toString().equalsIgnoreCase("CASE") && !tmp.toString().equalsIgnoreCase("LOOP")))) {
chrislovsund@177
  2451
                        endCount++;
chrislovsund@177
  2452
                    }
chrislovsund@177
  2453
chrislovsund@177
  2454
                    ts.move(off);
chrislovsund@177
  2455
                    ts.moveNext();
chrislovsund@177
  2456
                } else if ((endCount == 0) & (image.equalsIgnoreCase("PACKAGE"))) {
chrislovsund@177
  2457
                    return tmp;
chrislovsund@177
  2458
                } else if ((endCount == -1) && ((image.equalsIgnoreCase("PROCEDURE"))
chrislovsund@177
  2459
                        || (image.equalsIgnoreCase("FUNCTION")))) {
chrislovsund@177
  2460
                    return tmp;
chrislovsund@177
  2461
                } else if ((endCount == 0) & (image.equalsIgnoreCase("BODY"))) {
chrislovsund@177
  2462
                    boolean pre = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2463
                    Token<PlsqlTokenId> previous = ts.token();
chrislovsund@177
  2464
                    if ((pre != false) && (previous.text().toString().equalsIgnoreCase("PACKAGE"))) {
chrislovsund@177
  2465
                        return previous;
chrislovsund@177
  2466
                    }
chrislovsund@177
  2467
                }
chrislovsund@177
  2468
            }
chrislovsund@177
  2469
chrislovsund@177
  2470
            moveBack = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2471
            tmp = ts.token();
chrislovsund@177
  2472
        }
chrislovsund@177
  2473
chrislovsund@177
  2474
        return begin;
chrislovsund@177
  2475
    }
chrislovsund@177
  2476
chrislovsund@177
  2477
    /**
chrislovsund@177
  2478
     * Check whether this is a block comment, single line or multi lined comment
chrislovsund@362
  2479
     *
chrislovsund@177
  2480
     * @param current
chrislovsund@177
  2481
     * @param ts
chrislovsund@177
  2482
     * @return
chrislovsund@177
  2483
     */
chrislovsund@177
  2484
    private PlsqlBlock checkComment(Token<PlsqlTokenId> current, TokenSequence<PlsqlTokenId> ts) {
chrislovsund@362
  2485
        LOG.log(Level.FINE, "checkComment, ts.index()={0} current={1} ", new Object[]{ts.index(), current});
chrislovsund@177
  2486
        //If the line don't start with the comment ignore
chrislovsund@177
  2487
        String prefix = getPreceedingText(current.offset(tokenHierarchy), ts);
chrislovsund@177
  2488
        if (!prefix.trim().equals("")) {
chrislovsund@177
  2489
            return null;
chrislovsund@177
  2490
        }
chrislovsund@177
  2491
chrislovsund@177
  2492
        Token<PlsqlTokenId> commentBegin = current;
chrislovsund@177
  2493
        Token<PlsqlTokenId> commentEnd = current;
chrislovsund@177
  2494
        String text = commentBegin.text().toString();
chrislovsund@362
  2495
        boolean moveNext = getNextNonWhitespaceForComments(ts);
chrislovsund@362
  2496
        Token<PlsqlTokenId> tmp = ts.token();
chrislovsund@177
  2497
        boolean takeDesc = true;
chrislovsund@177
  2498
        String desc = getCommentDescription(text);
chrislovsund@177
  2499
        if (!desc.equals("COMMENT...")) {
chrislovsund@177
  2500
            takeDesc = false;
chrislovsund@177
  2501
        }
chrislovsund@177
  2502
chrislovsund@177
  2503
        while (moveNext) {
chrislovsund@177
  2504
            PlsqlTokenId tokenID = tmp.id();
chrislovsund@177
  2505
chrislovsund@177
  2506
            //We have come to the end of the view declaration
chrislovsund@177
  2507
            if (tokenID != PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
  2508
                break;
chrislovsund@177
  2509
            } else {
chrislovsund@177
  2510
                commentEnd = tmp;
chrislovsund@177
  2511
                if (takeDesc) {
chrislovsund@177
  2512
                    text = text + tmp.text().toString();
chrislovsund@177
  2513
                    desc = getCommentDescription(text);
chrislovsund@177
  2514
                    if (!desc.equals("COMMENT...")) {
chrislovsund@177
  2515
                        takeDesc = false;
chrislovsund@177
  2516
                    }
chrislovsund@177
  2517
                }
chrislovsund@362
  2518
                moveNext = getNextNonWhitespaceForComments(ts);
chrislovsund@177
  2519
                tmp = ts.token();
chrislovsund@177
  2520
            }
chrislovsund@177
  2521
        }
chrislovsund@177
  2522
chrislovsund@362
  2523
        ts.move(commentEnd.offset(tokenHierarchy));
chrislovsund@177
  2524
        ts.moveNext();
chrislovsund@177
  2525
chrislovsund@177
  2526
        //Calculate end offset
subslk@464
  2527
        if(commentEnd.id() == PlsqlTokenId.WHITESPACE ){
subslk@464
  2528
            ts.movePrevious();
subslk@464
  2529
            commentEnd = ts.token();
subslk@464
  2530
        }
chrislovsund@177
  2531
        int endOffset = commentEnd.offset(tokenHierarchy) + commentEnd.length();
chrislovsund@177
  2532
chrislovsund@362
  2533
        return new PlsqlBlock(commentBegin.offset(tokenHierarchy),
chrislovsund@177
  2534
                endOffset, desc, "", PlsqlBlockType.COMMENT);
chrislovsund@177
  2535
    }
chrislovsund@177
  2536
chrislovsund@177
  2537
    /**
chrislovsund@177
  2538
     * Method that will give the description of the comment fold
chrislovsund@362
  2539
     *
chrislovsund@177
  2540
     * @param text
chrislovsund@177
  2541
     * @return
chrislovsund@177
  2542
     */
chrislovsund@177
  2543
    private String getCommentDescription(String text) {
chrislovsund@177
  2544
        String description = "COMMENT...";
chrislovsund@177
  2545
chrislovsund@177
  2546
        //Get first -- character from begin to end
chrislovsund@177
  2547
        char[] textArr = text.toCharArray();
chrislovsund@177
  2548
        int begin = 0;
chrislovsund@177
  2549
        int end = 0;
chrislovsund@177
  2550
chrislovsund@177
  2551
        //Get the start character which is not -
chrislovsund@177
  2552
        int i = 0;
chrislovsund@177
  2553
        while (textArr.length > i) {
chrislovsund@177
  2554
            if ((textArr[i] != '-') && (textArr[i] != ' ')) {
chrislovsund@177
  2555
                begin = i;
chrislovsund@177
  2556
                break;
chrislovsund@177
  2557
            }
chrislovsund@177
  2558
            i++;
chrislovsund@177
  2559
        }
chrislovsund@177
  2560
chrislovsund@177
  2561
        //Get end character which is -
chrislovsund@177
  2562
        i++;
chrislovsund@177
  2563
        while (textArr.length > i) {
chrislovsund@177
  2564
            if (textArr[i] == '-') {
chrislovsund@177
  2565
                break;
chrislovsund@177
  2566
            }
chrislovsund@177
  2567
            i++;
chrislovsund@177
  2568
        }
chrislovsund@177
  2569
chrislovsund@177
  2570
        end = i;
chrislovsund@177
  2571
chrislovsund@177
  2572
        if (begin != 0) {
chrislovsund@177
  2573
            description = "-- " + text.substring(begin, end);
chrislovsund@177
  2574
        }
chrislovsund@177
  2575
chrislovsund@177
  2576
        return description;
chrislovsund@177
  2577
    }
chrislovsund@177
  2578
chrislovsund@177
  2579
    /**
chrislovsund@177
  2580
     * Check whether this is the start of a PROCEDURE/FUNCTION block
chrislovsund@362
  2581
     *
chrislovsund@177
  2582
     * @param methodToken
chrislovsund@177
  2583
     * @param ts
chrislovsund@177
  2584
     * @param type
chrislovsund@177
  2585
     * @return
chrislovsund@177
  2586
     */
chrislovsund@177
  2587
    private PlsqlBlock checkMethod(Token<PlsqlTokenId> methodToken, TokenSequence<PlsqlTokenId> ts, PlsqlBlockType type, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
  2588
        Token<PlsqlTokenId> methodBegin = methodToken;
chrislovsund@177
  2589
        Token<PlsqlTokenId> tmp = methodToken;
chrislovsund@177
  2590
        PlsqlBlock block = null;
chrislovsund@177
  2591
        List<PlsqlBlock> lstChild = new ArrayList<PlsqlBlock>();
chrislovsund@177
  2592
        boolean isFound = false;
chrislovsund@177
  2593
        boolean pragmaFound = false;
chrislovsund@177
  2594
        int colunCount = 0;
chrislovsund@177
  2595
        String methodName = "";
chrislovsund@177
  2596
        boolean moveNext = false;
chrislovsund@177
  2597
        int beginCount = 0; //workaround to identify end of method...
chrislovsund@177
  2598
chrislovsund@177
  2599
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
  2600
        if (sqlPlusLine(ts)) {
chrislovsund@177
  2601
            return null;
chrislovsund@177
  2602
        }
chrislovsund@177
  2603
chrislovsund@177
  2604
        //Get procedure/function name which is the next non whitespace token
chrislovsund@177
  2605
        moveNext = getNextNonWhitespace(ts, true);
chrislovsund@177
  2606
        tmp = ts.token();
chrislovsund@177
  2607
        if (moveNext == false) {
chrislovsund@177
  2608
            return block;
chrislovsund@177
  2609
        }
chrislovsund@177
  2610
chrislovsund@177
  2611
        methodName = tmp.text().toString();
chrislovsund@177
  2612
        methodName = checkForOtherSchema(ts, methodName);
chrislovsund@177
  2613
        String alias = "";
chrislovsund@177
  2614
        if (methodName.indexOf('&') != -1) {
jrechtacek@0
  2615
            alias = methodName;
chrislovsund@177
  2616
        }
chrislovsund@177
  2617
chrislovsund@177
  2618
        methodName = getDefine(methodName);
chrislovsund@177
  2619
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@177
  2620
        Token<PlsqlTokenId> previous = tmp;
chrislovsund@177
  2621
chrislovsund@177
  2622
        //Check whether there is the keyword 'IS' before ';'
chrislovsund@177
  2623
        while (moveNext) {
chrislovsund@177
  2624
            String image = tmp.text().toString();
chrislovsund@177
  2625
            PlsqlTokenId tokenID = tmp.id();
chrislovsund@177
  2626
chrislovsund@177
  2627
            if ((tmp != null) && (!image.equals(";")) && (!image.equalsIgnoreCase("END")) && (!previous.toString().equalsIgnoreCase("END")) && (tmp.offset(tokenHierarchy) > endParse)) { //end is added here for the abnormal case in code templates
chrislovsund@177
  2628
                break;
jrechtacek@0
  2629
            }
jrechtacek@0
  2630
chrislovsund@177
  2631
            //Increment colun count, if IS is not found before first break
chrislovsund@177
  2632
            if ((tokenID == PlsqlTokenId.OPERATOR) && image.equals(";")) {
chrislovsund@177
  2633
                ++colunCount;
chrislovsund@177
  2634
                boolean isEndFound = false;
chrislovsund@177
  2635
                int offset = ts.offset();
chrislovsund@177
  2636
                boolean preMove = false;
chrislovsund@177
  2637
                preMove = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2638
chrislovsund@177
  2639
                //workaround for issue with functions/procedures ending with End; (no name)
chrislovsund@177
  2640
                Token<PlsqlTokenId> previousNWS = ts.token();
chrislovsund@177
  2641
                PlsqlTokenId previd = previousNWS.id();
chrislovsund@177
  2642
                if ((preMove != false) && previousNWS.text().toString().equalsIgnoreCase("END")) {
chrislovsund@177
  2643
                    if (beginCount < 1) {
chrislovsund@177
  2644
                        isEndFound = true;
chrislovsund@177
  2645
                    }
chrislovsund@177
  2646
                } else {
chrislovsund@177
  2647
                    preMove = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2648
                    previousNWS = ts.token();
chrislovsund@177
  2649
                    if ((previd == PlsqlTokenId.IDENTIFIER || previd == PlsqlTokenId.KEYWORD)
chrislovsund@177
  2650
                            && previousNWS.text().toString().equalsIgnoreCase("END")) {
chrislovsund@177
  2651
                        isEndFound = true;
chrislovsund@177
  2652
                    }
chrislovsund@177
  2653
                }
chrislovsund@177
  2654
chrislovsund@177
  2655
                ts.move(offset);
chrislovsund@177
  2656
                if ((colunCount == 1) && (!isFound) && (!pragmaFound) && (!isEndFound)) {
chrislovsund@177
  2657
                    //Although we were looking for impl's we have found a def here
chrislovsund@177
  2658
                    ts.moveNext();
chrislovsund@177
  2659
                    ts.moveNext();
chrislovsund@177
  2660
                    if (type == PlsqlBlockType.PROCEDURE_IMPL) {
chrislovsund@177
  2661
                        block = new PlsqlBlock(methodBegin.offset(tokenHierarchy),
chrislovsund@177
  2662
                                ts.offset(), methodName, alias, PlsqlBlockType.PROCEDURE_DEF);
chrislovsund@177
  2663
                    } else {
chrislovsund@177
  2664
                        block = new PlsqlBlock(methodBegin.offset(tokenHierarchy),
chrislovsund@177
  2665
                                ts.offset(), methodName, alias, PlsqlBlockType.FUNCTION_DEF);
chrislovsund@177
  2666
                    }
chrislovsund@177
  2667
chrislovsund@177
  2668
                    return block;
chrislovsund@177
  2669
                }
chrislovsund@177
  2670
                ts.moveNext();
jrechtacek@0
  2671
            }
chrislovsund@177
  2672
chrislovsund@177
  2673
            //We might have come to the end of the procedure/function declaration
chrislovsund@177
  2674
            if (((tokenID == PlsqlTokenId.OPERATOR) && image.equals(";")) && isFound) {
chrislovsund@177
  2675
                //check whether previous Non white space token to the identifier is END
chrislovsund@177
  2676
                int offset = ts.offset();
chrislovsund@177
  2677
                boolean preMove = false;
chrislovsund@177
  2678
                preMove = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2679
                //workaround for issue with functions/procedures ending with End; (no name)
chrislovsund@177
  2680
                Token<PlsqlTokenId> previousNWS = ts.token();
chrislovsund@177
  2681
                String prevText = previousNWS.text().toString();
chrislovsund@177
  2682
                if ((preMove != false) && prevText.equalsIgnoreCase("END")) {
chrislovsund@177
  2683
                    if (beginCount <= 0) {
chrislovsund@177
  2684
                        ts.move(offset);
chrislovsund@177
  2685
                        moveNext = ts.moveNext();
chrislovsund@177
  2686
                        moveNext = ts.moveNext();
chrislovsund@177
  2687
                        block = new PlsqlBlock(methodBegin.offset(tokenHierarchy),
chrislovsund@177
  2688
                                ts.offset(), methodName, alias, type);
chrislovsund@177
  2689
                        checkPrefix(methodBegin.offset(tokenHierarchy), ts, block);
chrislovsund@177
  2690
                        break;
chrislovsund@177
  2691
                    }
chrislovsund@177
  2692
                } else {
chrislovsund@177
  2693
                    preMove = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2694
                    previousNWS = ts.token();
chrislovsund@177
  2695
                    if (previousNWS.text().toString().equalsIgnoreCase("END")) {
chrislovsund@177
  2696
                        if (beginCount <= 0) {
chrislovsund@177
  2697
                            ts.move(offset);
chrislovsund@177
  2698
                            moveNext = ts.moveNext();
chrislovsund@177
  2699
                            moveNext = ts.moveNext();
chrislovsund@177
  2700
                            block = new PlsqlBlock(methodBegin.offset(tokenHierarchy),
chrislovsund@177
  2701
                                    ts.offset(), methodName, alias, type);
chrislovsund@177
  2702
                            checkPrefix(methodBegin.offset(tokenHierarchy), ts, block);
chrislovsund@177
  2703
                            break;
chrislovsund@177
  2704
                        }
chrislovsund@177
  2705
                    }
chrislovsund@177
  2706
                }
chrislovsund@177
  2707
                ts.move(offset);
chrislovsund@177
  2708
                moveNext = ts.moveNext();
chrislovsund@177
  2709
            } else if ((tokenID == PlsqlTokenId.KEYWORD)
chrislovsund@177
  2710
                    && ((image.equalsIgnoreCase("PROCEDURE"))
chrislovsund@177
  2711
                    || (image.equalsIgnoreCase("FUNCTION"))
chrislovsund@177
  2712
                    || (image.equalsIgnoreCase("CURSOR")))) {
chrislovsund@177
  2713
                if (isFound && beginCount <= 0) {
chrislovsund@177
  2714
                    int beforeOff = tmp.offset(tokenHierarchy);
chrislovsund@177
  2715
chrislovsund@177
  2716
                    if (image.equalsIgnoreCase("PROCEDURE")) {
chrislovsund@177
  2717
                        PlsqlBlock child = checkMethod(tmp, ts, PlsqlBlockType.PROCEDURE_IMPL, lstChild);
chrislovsund@177
  2718
                        if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  2719
chrislovsund@177
  2720
                            ts.move(beforeOff);
chrislovsund@177
  2721
                            moveNext = ts.moveNext();
chrislovsund@177
  2722
                        } else {
chrislovsund@177
  2723
                            if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  2724
                                lstChild.add(child);
chrislovsund@177
  2725
                            }
chrislovsund@177
  2726
                        }
chrislovsund@177
  2727
                    } //Inner procedure
chrislovsund@177
  2728
                    else if (image.equalsIgnoreCase("FUNCTION")) {
chrislovsund@177
  2729
                        PlsqlBlock child = checkMethod(tmp, ts, PlsqlBlockType.FUNCTION_IMPL, lstChild);
chrislovsund@177
  2730
                        if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  2731
chrislovsund@177
  2732
                            ts.move(beforeOff);
chrislovsund@177
  2733
                            moveNext = ts.moveNext();
chrislovsund@177
  2734
                        } else {
chrislovsund@177
  2735
                            if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  2736
                                lstChild.add(child);
chrislovsund@177
  2737
                            }
chrislovsund@177
  2738
                        }
chrislovsund@177
  2739
                    } //Inner function
chrislovsund@177
  2740
                    else if (image.equalsIgnoreCase("CURSOR")) {
chrislovsund@177
  2741
                        PlsqlBlock child = checkCursor(tmp, ts, lstChild);
chrislovsund@177
  2742
                        if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  2743
chrislovsund@177
  2744
                            ts.move(beforeOff);
chrislovsund@177
  2745
                            moveNext = ts.moveNext();
chrislovsund@177
  2746
                        } else {
chrislovsund@177
  2747
                            if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  2748
                                lstChild.add(child);
chrislovsund@177
  2749
                            }
chrislovsund@177
  2750
                        }
chrislovsund@177
  2751
                    } //Inner cursor
chrislovsund@177
  2752
                } else {
chrislovsund@177
  2753
                    break;
chrislovsund@177
  2754
                }
chrislovsund@177
  2755
            } else if ((image.equalsIgnoreCase("IF")) && isFound) {
chrislovsund@177
  2756
                int beforeOff = tmp.offset(tokenHierarchy);
chrislovsund@177
  2757
                List children = checkIfBlock(tmp, ts, lstChild);
chrislovsund@177
  2758
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  2759
chrislovsund@177
  2760
                    ts.move(beforeOff);
chrislovsund@177
  2761
                    moveNext =
chrislovsund@177
  2762
                            ts.moveNext();
chrislovsund@177
  2763
                } else {
chrislovsund@177
  2764
                    for (int i = 0; i
chrislovsund@177
  2765
                            < children.size(); i++) {
chrislovsund@177
  2766
                        PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@177
  2767
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  2768
                            lstChild.add(child);
chrislovsund@177
  2769
                        }
chrislovsund@177
  2770
                    }
chrislovsund@177
  2771
                }
chrislovsund@177
  2772
            } //If block
chrislovsund@177
  2773
            else if ((image.equalsIgnoreCase("CASE")) && isFound) {
chrislovsund@177
  2774
                int beforeOff = tmp.offset(tokenHierarchy);
chrislovsund@177
  2775
                List children = checkCaseBlock(tmp, ts, lstChild, false);
chrislovsund@177
  2776
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  2777
chrislovsund@177
  2778
                    ts.move(beforeOff);
chrislovsund@371
  2779
                    moveNext = ts.moveNext();
chrislovsund@177
  2780
                } else {
chrislovsund@177
  2781
                    for (int i = 0; i
chrislovsund@177
  2782
                            < children.size(); i++) {
chrislovsund@177
  2783
                        PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@177
  2784
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  2785
                            lstChild.add(child);
chrislovsund@177
  2786
                        }
chrislovsund@177
  2787
                    }
chrislovsund@177
  2788
                }
chrislovsund@177
  2789
            } else if ((tokenID == PlsqlTokenId.KEYWORD)
chrislovsund@177
  2790
                    && ((image.equalsIgnoreCase("LOOP"))
chrislovsund@177
  2791
                    || (image.equalsIgnoreCase("WHILE"))
chrislovsund@177
  2792
                    || (image.equalsIgnoreCase("FOR")))) {
chrislovsund@177
  2793
                if (isFound) {
chrislovsund@177
  2794
                    int beforeOff = tmp.offset(tokenHierarchy);
chrislovsund@177
  2795
                    if (!unsuccessBlocks.contains(beforeOff)) {
chrislovsund@177
  2796
                        PlsqlBlock child = checkLoopBlock(tmp, ts, lstChild);
chrislovsund@177
  2797
                        if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  2798
                            unsuccessBlocks.add(beforeOff);
chrislovsund@177
  2799
                            ts.move(beforeOff);
chrislovsund@177
  2800
                            moveNext = ts.moveNext();
chrislovsund@177
  2801
                        } else {
chrislovsund@177
  2802
                            if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  2803
                                lstChild.add(child);
chrislovsund@177
  2804
                            }
chrislovsund@177
  2805
                        }
chrislovsund@177
  2806
                    }
chrislovsund@177
  2807
                }
chrislovsund@177
  2808
            } else if ((tokenID == PlsqlTokenId.KEYWORD) && (image.equalsIgnoreCase("TABLE")
chrislovsund@177
  2809
                    || image.equalsIgnoreCase("INDEX")
chrislovsund@177
  2810
                    || image.equalsIgnoreCase("SELECT")
chrislovsund@177
  2811
                    || image.equalsIgnoreCase("UPDATE")
chrislovsund@177
  2812
                    || image.equalsIgnoreCase("DELETE")
chrislovsund@177
  2813
                    || image.equalsIgnoreCase("INSERT")
chrislovsund@177
  2814
                    || image.equalsIgnoreCase("MERGE")
chrislovsund@177
  2815
                    || image.equalsIgnoreCase("DROP")
chrislovsund@177
  2816
                    || image.equalsIgnoreCase("SEQUENCE"))) {
chrislovsund@177
  2817
                if (!isNotBlockStart(tmp, ts)) {
chrislovsund@177
  2818
                    int offset = tmp.offset(tokenHierarchy);
chrislovsund@177
  2819
                    PlsqlBlock child = checkStatementBlock(tmp, ts, parentBlocks);
chrislovsund@177
  2820
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  2821
chrislovsund@177
  2822
                        ts.move(offset);
chrislovsund@177
  2823
                        ts.moveNext();
chrislovsund@177
  2824
                    } else {
chrislovsund@177
  2825
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  2826
                            lstChild.add(child);
chrislovsund@177
  2827
                        }
chrislovsund@177
  2828
                    }
chrislovsund@177
  2829
                }
chrislovsund@177
  2830
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
  2831
                //only single comment line
chrislovsund@177
  2832
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
  2833
                    customStartToken = tmp;
chrislovsund@177
  2834
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
  2835
                    if (customStartToken != null) {
chrislovsund@177
  2836
                        String name = customStartToken.text().toString();
chrislovsund@177
  2837
                        int index = name.toUpperCase(Locale.ENGLISH).indexOf("<FOLD>");
chrislovsund@177
  2838
                        name =
chrislovsund@177
  2839
                                name.substring(index + 7).trim();
chrislovsund@177
  2840
                        if (ts.moveNext()) {
chrislovsund@177
  2841
                            tmp = ts.token();
chrislovsund@177
  2842
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@177
  2843
                                    tmp.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
  2844
                            customFoldBlocks.add(custom);
chrislovsund@177
  2845
                        }
chrislovsund@177
  2846
                        customStartToken = null;
chrislovsund@177
  2847
                    }
chrislovsund@177
  2848
                } else {
chrislovsund@177
  2849
                    PlsqlBlock child = checkComment(tmp, ts);
chrislovsund@177
  2850
                    if ((child != null) && (checkExisting(child, lstChild) == false)) {
chrislovsund@177
  2851
                        lstChild.add(child);
chrislovsund@177
  2852
                    }
chrislovsund@177
  2853
                }
chrislovsund@177
  2854
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@177
  2855
                int start = tmp.offset(tokenHierarchy);
chrislovsund@177
  2856
                PlsqlBlock child = new PlsqlBlock(start,
chrislovsund@177
  2857
                        start + tmp.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@371
  2858
                if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  2859
                    lstChild.add(child);
chrislovsund@177
  2860
                }
chrislovsund@177
  2861
            } else if (tokenID == PlsqlTokenId.KEYWORD && (image.equalsIgnoreCase("BEGIN"))) {
chrislovsund@177
  2862
                beginCount++;
chrislovsund@177
  2863
            } else if (tokenID == PlsqlTokenId.KEYWORD && image.equalsIgnoreCase("END")) {
chrislovsund@177
  2864
                int off = ts.offset();
chrislovsund@177
  2865
                if (getNextNonWhitespace(ts, true)) {
chrislovsund@177
  2866
                    tmp = ts.token();
chrislovsund@177
  2867
                }
chrislovsund@177
  2868
chrislovsund@177
  2869
                if ((tmp.text().toString().equals(";")) || (tmp.id() == PlsqlTokenId.IDENTIFIER)
chrislovsund@177
  2870
                        || (tmp.id() == PlsqlTokenId.KEYWORD && (!tmp.toString().equalsIgnoreCase("IF")
chrislovsund@177
  2871
                        && !tmp.toString().equalsIgnoreCase("CASE") && !tmp.toString().equalsIgnoreCase("LOOP")))) {
chrislovsund@177
  2872
                    beginCount--;
chrislovsund@177
  2873
                }
chrislovsund@177
  2874
chrislovsund@177
  2875
                ts.move(off);
chrislovsund@177
  2876
                ts.moveNext();
chrislovsund@177
  2877
                tmp = ts.token();
chrislovsund@177
  2878
            } else if (tokenID == PlsqlTokenId.KEYWORD && image.equalsIgnoreCase("PRAGMA")) {
chrislovsund@177
  2879
                pragmaFound = true;
chrislovsund@177
  2880
            } else {
chrislovsund@177
  2881
                //Mark when we come to 'IS'
chrislovsund@177
  2882
                if ((tokenID == PlsqlTokenId.KEYWORD)
chrislovsund@177
  2883
                        && ((image.equalsIgnoreCase("IS")))) {
chrislovsund@177
  2884
                    isFound = true;
chrislovsund@177
  2885
                }
jrechtacek@0
  2886
            }
chrislovsund@177
  2887
            if (tokenID != PlsqlTokenId.WHITESPACE) {
chrislovsund@177
  2888
                previous = tmp;
jrechtacek@0
  2889
            }
chrislovsund@177
  2890
chrislovsund@177
  2891
            moveNext = ts.moveNext();
jrechtacek@0
  2892
            tmp = ts.token();
chrislovsund@177
  2893
        }
chrislovsund@177
  2894
chrislovsund@177
  2895
        if (block != null) {
chrislovsund@177
  2896
            //check whether there is a parent block
chrislovsund@177
  2897
            PlsqlBlock parent = getParentBlock(blockHierarchy, block.getStartOffset(), block.getEndOffset());
chrislovsund@177
  2898
            if ((parent != null) && (parent.getName().equals(block.getName()))) {
chrislovsund@177
  2899
                if (parent.getEndOffset() == block.getEndOffset()) {
chrislovsund@177
  2900
                    return null;
chrislovsund@177
  2901
                }
jrechtacek@0
  2902
            }
jrechtacek@0
  2903
chrislovsund@177
  2904
            //add children
chrislovsund@177
  2905
            addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  2906
        }
chrislovsund@177
  2907
chrislovsund@177
  2908
        return block;
chrislovsund@177
  2909
    }
chrislovsund@177
  2910
chrislovsund@177
  2911
    /**
chrislovsund@177
  2912
     * Check whether this is the start of a PACKAGE block
chrislovsund@362
  2913
     *
chrislovsund@177
  2914
     * @param tempToken
chrislovsund@177
  2915
     * @param ts
chrislovsund@177
  2916
     * @return
chrislovsund@177
  2917
     */
chrislovsund@177
  2918
    private PlsqlBlock checkPackage(Token<PlsqlTokenId> packToken, TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
  2919
        Token<PlsqlTokenId> packBegin = packToken;
chrislovsund@177
  2920
        Token<PlsqlTokenId> tmp = packToken;
chrislovsund@177
  2921
        Token<PlsqlTokenId> tmpPre = packToken;
chrislovsund@177
  2922
        boolean isFound = false;
chrislovsund@177
  2923
        String packageName = "";
chrislovsund@177
  2924
        boolean isPackageBody = false;
chrislovsund@177
  2925
        boolean moveNext = false;
chrislovsund@177
  2926
        PlsqlBlock block = null;
chrislovsund@177
  2927
        List<PlsqlBlock> lstChild = new ArrayList<PlsqlBlock>();
chrislovsund@177
  2928
        int beginCount = 0;
chrislovsund@177
  2929
chrislovsund@177
  2930
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
  2931
        if (sqlPlusLine(ts)) {
chrislovsund@177
  2932
            return null;
chrislovsund@177
  2933
        }
chrislovsund@177
  2934
chrislovsund@177
  2935
        //Get package name which is the next non whitespace token in spec
chrislovsund@177
  2936
        moveNext = getNextNonWhitespace(ts, true);
chrislovsund@177
  2937
        tmp = ts.token();
chrislovsund@177
  2938
        if (moveNext == false) {
jrechtacek@0
  2939
            return block;
chrislovsund@177
  2940
        }
chrislovsund@177
  2941
chrislovsund@177
  2942
        if (tmp.text().toString().equalsIgnoreCase("BODY")) {
chrislovsund@177
  2943
            isPackageBody = true;
jrechtacek@0
  2944
            moveNext = getNextNonWhitespace(ts, true);
jrechtacek@0
  2945
            tmp = ts.token();
chrislovsund@177
  2946
            if (moveNext == false) {
chrislovsund@177
  2947
                return block;
jrechtacek@0
  2948
            }
chrislovsund@177
  2949
        }
chrislovsund@177
  2950
chrislovsund@177
  2951
        packageName = tmp.text().toString();
chrislovsund@177
  2952
        packageName = checkForOtherSchema(ts, packageName);
chrislovsund@177
  2953
        String alias = "";
chrislovsund@177
  2954
        if (packageName.indexOf('&') != -1) {
chrislovsund@177
  2955
            alias = packageName;
chrislovsund@177
  2956
        } else if (hasDefineKey(packageName)) {
chrislovsund@177
  2957
            alias = '&' + getDefineKey(packageName);
chrislovsund@177
  2958
        }
chrislovsund@177
  2959
chrislovsund@177
  2960
        packageName = getDefine(packageName);
chrislovsund@177
  2961
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@177
  2962
chrislovsund@177
  2963
        while (moveNext) {
chrislovsund@177
  2964
            String image = tmp.text().toString();
chrislovsund@177
  2965
            PlsqlTokenId tokenID = tmp.id();
chrislovsund@177
  2966
chrislovsund@371
  2967
            if ((!image.equals(";")) && (tmp.offset(tokenHierarchy) > endParse)) {
chrislovsund@177
  2968
                break;
chrislovsund@177
  2969
            }
chrislovsund@177
  2970
chrislovsund@177
  2971
            //We might have come to the end of the package
chrislovsund@177
  2972
            if (((tokenID == PlsqlTokenId.OPERATOR) && (image.equals(";") || (image.equals("/") && checkForOnlyChar(ts, ts.offset())))) && (isFound)
chrislovsund@177
  2973
                    && ((tmpPre.text().toString().equalsIgnoreCase(packageName))
chrislovsund@177
  2974
                    || ((!alias.equals("")) && (tmpPre.text().toString().equalsIgnoreCase(alias)))
chrislovsund@177
  2975
                    || ((tmpPre.text().toString().equalsIgnoreCase("END")) && (beginCount < 0)))) {
chrislovsund@177
  2976
                boolean isPackage = false;
chrislovsund@177
  2977
                if (tmpPre.text().toString().equalsIgnoreCase(packageName)
chrislovsund@177
  2978
                        || tmpPre.text().toString().equalsIgnoreCase(alias)) {
chrislovsund@177
  2979
                    //check whether previous Non white space token to the identifier is END
chrislovsund@177
  2980
                    int offset = ts.offset();
chrislovsund@371
  2981
                    boolean preMove = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2982
                    preMove = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  2983
                    Token<PlsqlTokenId> previousNWS = ts.token();
chrislovsund@177
  2984
chrislovsund@177
  2985
                    ts.move(offset);
chrislovsund@177
  2986
                    ts.moveNext();
chrislovsund@177
  2987
chrislovsund@177
  2988
                    if ((preMove != false)
chrislovsund@177
  2989
                            && previousNWS.text().toString().equalsIgnoreCase("END")) {
chrislovsund@177
  2990
                        isPackage = true;
chrislovsund@177
  2991
                    }
chrislovsund@177
  2992
                } else if ((tmpPre.text().toString().equalsIgnoreCase("END")) && (beginCount < 0)) {
chrislovsund@177
  2993
                    isPackage = true;
chrislovsund@177
  2994
                }
chrislovsund@177
  2995
chrislovsund@177
  2996
                //If this is a package end create the block
chrislovsund@177
  2997
                if (isPackage) {
chrislovsund@177
  2998
                    PlsqlBlockType type = PlsqlBlockType.PACKAGE;
chrislovsund@177
  2999
chrislovsund@177
  3000
                    if (isPackageBody) {
chrislovsund@177
  3001
                        type = PlsqlBlockType.PACKAGE_BODY;
chrislovsund@177
  3002
                    }
chrislovsund@177
  3003
chrislovsund@177
  3004
                    ts.moveNext();
chrislovsund@177
  3005
chrislovsund@177
  3006
                    block = new PlsqlBlock(packBegin.offset(tokenHierarchy),
chrislovsund@177
  3007
                            ts.offset(), packageName, alias, type);
chrislovsund@177
  3008
                    checkPrefix(packBegin.offset(tokenHierarchy), ts, block);
chrislovsund@177
  3009
                    break;
chrislovsund@177
  3010
                }
chrislovsund@177
  3011
            } else if ((tokenID == PlsqlTokenId.KEYWORD)
chrislovsund@177
  3012
                    && ((image.equalsIgnoreCase("PROCEDURE"))
chrislovsund@177
  3013
                    || (image.equalsIgnoreCase("FUNCTION"))
chrislovsund@177
  3014
                    || (image.equalsIgnoreCase("CURSOR")))) {
chrislovsund@177
  3015
                if (isFound) {
chrislovsund@177
  3016
                    int beforeOff = tmp.offset(tokenHierarchy);
chrislovsund@177
  3017
chrislovsund@177
  3018
                    if (image.equalsIgnoreCase("PROCEDURE")) {
chrislovsund@177
  3019
                        PlsqlBlock child = checkMethod(tmp, ts, PlsqlBlockType.PROCEDURE_IMPL, lstChild);
chrislovsund@177
  3020
                        if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3021
chrislovsund@177
  3022
                            ts.move(beforeOff);
chrislovsund@177
  3023
                            ts.moveNext();
chrislovsund@177
  3024
                        } else {
chrislovsund@177
  3025
                            if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3026
                                lstChild.add(child);
chrislovsund@177
  3027
                            }
chrislovsund@177
  3028
                        }
chrislovsund@177
  3029
                    } //Inner procedure
chrislovsund@177
  3030
                    else if (image.equalsIgnoreCase("FUNCTION")) {
chrislovsund@177
  3031
                        PlsqlBlock child = checkMethod(tmp, ts, PlsqlBlockType.FUNCTION_IMPL, lstChild);
chrislovsund@177
  3032
                        if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3033
chrislovsund@177
  3034
                            ts.move(beforeOff);
chrislovsund@177
  3035
                            ts.moveNext();
chrislovsund@177
  3036
                        } else {
chrislovsund@177
  3037
                            if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3038
                                lstChild.add(child);
chrislovsund@177
  3039
                            }
chrislovsund@177
  3040
                        }
chrislovsund@177
  3041
                    } //Inner function
chrislovsund@177
  3042
                    else if (image.equalsIgnoreCase("CURSOR")) {
chrislovsund@177
  3043
                        PlsqlBlock child = checkCursor(tmp, ts, lstChild);
chrislovsund@177
  3044
                        if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3045
chrislovsund@177
  3046
                            ts.move(beforeOff);
chrislovsund@177
  3047
                            ts.moveNext();
chrislovsund@177
  3048
                        } else {
chrislovsund@177
  3049
                            if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3050
                                lstChild.add(child);
chrislovsund@177
  3051
                            }
chrislovsund@177
  3052
                        }
chrislovsund@177
  3053
                    } //Inner cursor
chrislovsund@177
  3054
chrislovsund@177
  3055
                } else {
chrislovsund@177
  3056
                    break;
chrislovsund@177
  3057
                }
chrislovsund@177
  3058
            } else if (tokenID == PlsqlTokenId.KEYWORD && (image.equalsIgnoreCase("BEGIN"))) {
chrislovsund@177
  3059
                beginCount++;
chrislovsund@177
  3060
            } else if ((tokenID == PlsqlTokenId.KEYWORD)
chrislovsund@177
  3061
                    && (image.equalsIgnoreCase("END"))) {
chrislovsund@177
  3062
                int off = ts.offset();
chrislovsund@177
  3063
                if (getNextNonWhitespace(ts, true)) {
chrislovsund@177
  3064
                    tmp = ts.token();
chrislovsund@177
  3065
                }
chrislovsund@177
  3066
chrislovsund@177
  3067
                if ((tmp.text().toString().equals(";")) || (tmp.id() == PlsqlTokenId.IDENTIFIER)
chrislovsund@177
  3068
                        || (tmp.id() == PlsqlTokenId.KEYWORD && (!tmp.toString().equalsIgnoreCase("IF")
chrislovsund@177
  3069
                        && !tmp.toString().equalsIgnoreCase("CASE") && !tmp.toString().equalsIgnoreCase("LOOP")))) {
chrislovsund@177
  3070
                    beginCount--;
chrislovsund@177
  3071
                }
chrislovsund@177
  3072
chrislovsund@177
  3073
                ts.move(off);
chrislovsund@177
  3074
                ts.moveNext();
chrislovsund@177
  3075
                tmp = ts.token();
chrislovsund@177
  3076
            } else if ((tokenID == PlsqlTokenId.KEYWORD)
chrislovsund@177
  3077
                    && ((image.equalsIgnoreCase("CREATE")) || (image.equalsIgnoreCase("PACKAGE")))) {
chrislovsund@177
  3078
                return block;
chrislovsund@177
  3079
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
  3080
                //only single comment line
chrislovsund@177
  3081
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
  3082
                    customStartToken = tmp;
chrislovsund@177
  3083
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
  3084
                    if (customStartToken != null) {
chrislovsund@177
  3085
                        String name = customStartToken.text().toString();
chrislovsund@177
  3086
                        int index = name.toUpperCase(Locale.ENGLISH).indexOf("<FOLD>");
chrislovsund@177
  3087
                        name = name.substring(index + 7).trim();
chrislovsund@177
  3088
                        if (ts.moveNext()) {
chrislovsund@177
  3089
                            tmp = ts.token();
chrislovsund@177
  3090
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@177
  3091
                                    tmp.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
  3092
                            customFoldBlocks.add(custom);
chrislovsund@177
  3093
                        }
chrislovsund@177
  3094
                        customStartToken = null;
chrislovsund@177
  3095
                    }
chrislovsund@177
  3096
                } else {
chrislovsund@177
  3097
                    PlsqlBlock child = checkComment(tmp, ts);
chrislovsund@177
  3098
                    if ((child != null) && (checkExisting(child, lstChild) == false)) {
chrislovsund@177
  3099
                        lstChild.add(child);
chrislovsund@177
  3100
                    }
chrislovsund@177
  3101
                }
chrislovsund@177
  3102
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@177
  3103
                int start = tmp.offset(tokenHierarchy);
chrislovsund@177
  3104
                PlsqlBlock child = new PlsqlBlock(start,
chrislovsund@177
  3105
                        start + tmp.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@371
  3106
                if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3107
                    lstChild.add(child);
chrislovsund@177
  3108
                }
chrislovsund@177
  3109
            } else {
chrislovsund@177
  3110
                //Mark when we come to 'IS'
chrislovsund@177
  3111
                if ((tokenID == PlsqlTokenId.KEYWORD)
chrislovsund@177
  3112
                        && ((image.equalsIgnoreCase("IS")) || (image.equalsIgnoreCase("AS")))) {
chrislovsund@177
  3113
                    isFound = true;
chrislovsund@177
  3114
                }
chrislovsund@177
  3115
            }
chrislovsund@177
  3116
chrislovsund@177
  3117
            if (tokenID != PlsqlTokenId.WHITESPACE) {//previous non whitespace token
chrislovsund@177
  3118
chrislovsund@177
  3119
                tmpPre = tmp;
chrislovsund@177
  3120
            }
chrislovsund@177
  3121
chrislovsund@177
  3122
            moveNext = ts.moveNext();
chrislovsund@177
  3123
            tmp = ts.token();
chrislovsund@177
  3124
        }
chrislovsund@177
  3125
chrislovsund@177
  3126
        if (block != null) {
chrislovsund@177
  3127
            //add children
chrislovsund@177
  3128
            addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  3129
chrislovsund@177
  3130
            //Add immediate children
chrislovsund@177
  3131
            addImmediateChildren(block, parentBlocks);
chrislovsund@177
  3132
        }
chrislovsund@177
  3133
chrislovsund@177
  3134
        return block;
chrislovsund@177
  3135
    }
chrislovsund@177
  3136
chrislovsund@177
  3137
    /**
chrislovsund@177
  3138
     * Method that will check declare end blocks
chrislovsund@362
  3139
     *
chrislovsund@177
  3140
     * @param current
chrislovsund@177
  3141
     * @param ts
chrislovsund@177
  3142
     * @param parentBlocks
chrislovsund@177
  3143
     * @returns
chrislovsund@177
  3144
     */
chrislovsund@177
  3145
    private PlsqlBlock checkDeclareBlock(Token<PlsqlTokenId> current, TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
  3146
        Token<PlsqlTokenId> declareBegin;
chrislovsund@177
  3147
        Token<PlsqlTokenId> token = null;
chrislovsund@177
  3148
        boolean moveNext = false;
chrislovsund@177
  3149
        boolean isBeginFound = false;
chrislovsund@177
  3150
        List<PlsqlBlock> lstChild = new ArrayList<PlsqlBlock>();
chrislovsund@177
  3151
        PlsqlBlock block = null;
chrislovsund@177
  3152
chrislovsund@177
  3153
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
  3154
        if (sqlPlusLine(ts)) {
chrislovsund@177
  3155
            return null;
chrislovsund@177
  3156
        }
chrislovsund@177
  3157
chrislovsund@177
  3158
        moveNext = ts.moveNext();
chrislovsund@177
  3159
        token = ts.token();
chrislovsund@177
  3160
        declareBegin = current;
chrislovsund@177
  3161
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@177
  3162
chrislovsund@177
  3163
        while (moveNext) {
chrislovsund@177
  3164
            PlsqlTokenId tokenID = token.id();
chrislovsund@177
  3165
            String image = token.text().toString();
chrislovsund@177
  3166
chrislovsund@177
  3167
            if ((token != null) && (!image.equals(";")) && (token.offset(tokenHierarchy) > endParse)) {
chrislovsund@177
  3168
                break;
chrislovsund@177
  3169
            }
chrislovsund@177
  3170
chrislovsund@177
  3171
            //We have come to the end of the comment
chrislovsund@177
  3172
            if ((tokenID == PlsqlTokenId.OPERATOR) && ((image.equals("/") && checkForOnlyChar(ts, ts.offset())) || image.equals(";"))) {
chrislovsund@177
  3173
                //check whether its END; or END before /
chrislovsund@177
  3174
                boolean movePre = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  3175
                Token<PlsqlTokenId> pre = ts.token();
chrislovsund@177
  3176
                if (!movePre) {
chrislovsund@177
  3177
                    ts.move(token.offset(tokenHierarchy));
chrislovsund@177
  3178
                    ts.moveNext();
chrislovsund@177
  3179
                }
chrislovsund@177
  3180
chrislovsund@177
  3181
                if (image.equals("/")) {
chrislovsund@177
  3182
                    if (pre.toString().equals(";")) {
chrislovsund@177
  3183
                        movePre = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  3184
                        pre = ts.token();
chrislovsund@177
  3185
                        if ((movePre) && (pre.toString().equalsIgnoreCase("END"))) {
chrislovsund@177
  3186
                            ts.move(token.offset(tokenHierarchy));
chrislovsund@177
  3187
                            ts.moveNext();
chrislovsund@177
  3188
                            ts.moveNext();
chrislovsund@177
  3189
                            block = new PlsqlBlock(declareBegin.offset(tokenHierarchy),
chrislovsund@177
  3190
                                    ts.offset(), "", "", PlsqlBlockType.DECLARE_END);
chrislovsund@177
  3191
                            removeChildBegin(block);
chrislovsund@177
  3192
                            break;
chrislovsund@177
  3193
                        }
chrislovsund@177
  3194
                    } else {
chrislovsund@177
  3195
                        //something has gone wrong '/' is a terminal
chrislovsund@177
  3196
                        break;
chrislovsund@177
  3197
                    }
chrislovsund@177
  3198
                } else {
chrislovsund@177
  3199
                    if ((movePre) && (pre.toString().equalsIgnoreCase("END"))) {
chrislovsund@177
  3200
                        ts.move(token.offset(tokenHierarchy));
chrislovsund@177
  3201
                        ts.moveNext();
chrislovsund@177
  3202
                        ts.moveNext();
chrislovsund@177
  3203
                        block = new PlsqlBlock(declareBegin.offset(tokenHierarchy),
chrislovsund@177
  3204
                                ts.offset(), "", "", PlsqlBlockType.DECLARE_END);
chrislovsund@177
  3205
                        removeChildBegin(block);
chrislovsund@177
  3206
                        break;
chrislovsund@177
  3207
                    }
chrislovsund@177
  3208
                }
chrislovsund@177
  3209
                ts.move(token.offset(tokenHierarchy));
chrislovsund@177
  3210
                ts.moveNext();
chrislovsund@177
  3211
            } else if (image.equalsIgnoreCase("CURSOR")) {
chrislovsund@177
  3212
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3213
                PlsqlBlock child = checkCursor(token, ts, lstChild);
chrislovsund@177
  3214
                if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3215
chrislovsund@177
  3216
                    ts.move(beforeOff);
chrislovsund@177
  3217
                    moveNext = ts.moveNext();
chrislovsund@177
  3218
                } else {
chrislovsund@177
  3219
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3220
                        lstChild.add(child);
chrislovsund@177
  3221
                    }
chrislovsund@177
  3222
                }
chrislovsund@177
  3223
            } else if (image.equalsIgnoreCase("PROCEDURE")) {
chrislovsund@177
  3224
                if (isBeginFound) {//Can be there only before begin in a declare block
chrislovsund@177
  3225
chrislovsund@177
  3226
                    break;
chrislovsund@177
  3227
                }
chrislovsund@177
  3228
chrislovsund@177
  3229
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3230
                PlsqlBlock child = checkMethod(token, ts, PlsqlBlockType.PROCEDURE_IMPL, lstChild);
chrislovsund@177
  3231
                if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3232
chrislovsund@177
  3233
                    ts.move(beforeOff);
chrislovsund@177
  3234
                    moveNext = ts.moveNext();
chrislovsund@177
  3235
                } else {
chrislovsund@177
  3236
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3237
                        lstChild.add(child);
chrislovsund@177
  3238
                    }
chrislovsund@177
  3239
                }
chrislovsund@177
  3240
            } else if (image.equalsIgnoreCase("FUNCTION")) {
chrislovsund@177
  3241
                if (isBeginFound) {//Can be there only before begin in a declare block
chrislovsund@177
  3242
chrislovsund@177
  3243
                    break;
chrislovsund@177
  3244
                }
chrislovsund@177
  3245
chrislovsund@177
  3246
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3247
                PlsqlBlock child = checkMethod(token, ts, PlsqlBlockType.FUNCTION_IMPL, lstChild);
chrislovsund@177
  3248
                if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3249
chrislovsund@177
  3250
                    ts.move(beforeOff);
chrislovsund@177
  3251
                    moveNext = ts.moveNext();
chrislovsund@177
  3252
                } else {
chrislovsund@177
  3253
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3254
                        lstChild.add(child);
chrislovsund@177
  3255
                    }
chrislovsund@177
  3256
                }
chrislovsund@177
  3257
            } else if (isBeginFound && image.equalsIgnoreCase("DECLARE")) {
chrislovsund@177
  3258
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3259
                PlsqlBlock child = checkDeclareBlock(token, ts, lstChild);
chrislovsund@177
  3260
                if (child != null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3261
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3262
                        lstChild.add(child);
chrislovsund@177
  3263
                    }
chrislovsund@177
  3264
                }
chrislovsund@177
  3265
            } else if (image.equalsIgnoreCase("BEGIN")) {
chrislovsund@177
  3266
                if (isBeginFound) {
chrislovsund@177
  3267
                    int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3268
                    PlsqlBlock child = checkBeginBlock(token, ts, lstChild);
chrislovsund@177
  3269
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3270
chrislovsund@177
  3271
                        ts.move(beforeOff);
chrislovsund@177
  3272
                        moveNext = ts.moveNext();
chrislovsund@177
  3273
                    } else {
chrislovsund@177
  3274
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3275
                            lstChild.add(child);
chrislovsund@177
  3276
                        }
chrislovsund@177
  3277
                    }
chrislovsund@177
  3278
                } else {
chrislovsund@177
  3279
                    isBeginFound = true;
chrislovsund@177
  3280
                }
chrislovsund@177
  3281
            } else if (image.equalsIgnoreCase("IF")) {
chrislovsund@177
  3282
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3283
                List children = checkIfBlock(token, ts, lstChild);
chrislovsund@177
  3284
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3285
chrislovsund@177
  3286
                    ts.move(beforeOff);
chrislovsund@177
  3287
                    moveNext = ts.moveNext();
chrislovsund@177
  3288
                } else {
chrislovsund@177
  3289
                    for (int i = 0; i < children.size(); i++) {
chrislovsund@177
  3290
                        PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@177
  3291
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3292
                            lstChild.add(child);
chrislovsund@177
  3293
                        }
chrislovsund@177
  3294
                    }
chrislovsund@177
  3295
                }
chrislovsund@177
  3296
            } else if (image.equalsIgnoreCase("CASE")) {
chrislovsund@177
  3297
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3298
                List children = checkCaseBlock(token, ts, lstChild, false);
chrislovsund@177
  3299
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3300
chrislovsund@177
  3301
                    ts.move(beforeOff);
chrislovsund@177
  3302
                    moveNext = ts.moveNext();
chrislovsund@177
  3303
                } else {
chrislovsund@177
  3304
                    for (int i = 0; i < children.size(); i++) {
chrislovsund@177
  3305
                        PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@177
  3306
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3307
                            lstChild.add(child);
chrislovsund@177
  3308
                        }
chrislovsund@177
  3309
                    }
chrislovsund@177
  3310
                }
chrislovsund@177
  3311
            } else if (image.equalsIgnoreCase("LOOP")
chrislovsund@177
  3312
                    || image.equalsIgnoreCase("WHILE")
chrislovsund@177
  3313
                    || image.equalsIgnoreCase("FOR")) {
chrislovsund@177
  3314
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3315
                if (!unsuccessBlocks.contains(beforeOff)) {
chrislovsund@177
  3316
                    PlsqlBlock child = checkLoopBlock(token, ts, lstChild);
chrislovsund@177
  3317
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3318
                        unsuccessBlocks.add(beforeOff);
chrislovsund@177
  3319
                        ts.move(beforeOff);
chrislovsund@177
  3320
                        moveNext = ts.moveNext();
chrislovsund@177
  3321
                    } else {
chrislovsund@177
  3322
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3323
                            lstChild.add(child);
chrislovsund@177
  3324
                        }
chrislovsund@177
  3325
                    }
chrislovsund@177
  3326
                }
chrislovsund@177
  3327
            } else if (image.equalsIgnoreCase("TABLE")
chrislovsund@177
  3328
                    || image.equalsIgnoreCase("INDEX")
chrislovsund@177
  3329
                    || image.equalsIgnoreCase("SELECT")
chrislovsund@177
  3330
                    || image.equalsIgnoreCase("UPDATE")
chrislovsund@177
  3331
                    || image.equalsIgnoreCase("DELETE")
chrislovsund@177
  3332
                    || image.equalsIgnoreCase("INSERT")
chrislovsund@177
  3333
                    || image.equalsIgnoreCase("MERGE")
chrislovsund@177
  3334
                    || image.equalsIgnoreCase("DROP")
chrislovsund@177
  3335
                    || image.equalsIgnoreCase("SEQUENCE")) {
chrislovsund@177
  3336
                if (!isNotBlockStart(token, ts)) {
chrislovsund@177
  3337
                    int offset = token.offset(tokenHierarchy);
chrislovsund@177
  3338
                    PlsqlBlock child = checkStatementBlock(token, ts, parentBlocks);
chrislovsund@177
  3339
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3340
chrislovsund@177
  3341
                        ts.move(offset);
chrislovsund@177
  3342
                        ts.moveNext();
chrislovsund@177
  3343
                    } else {
chrislovsund@177
  3344
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3345
                            lstChild.add(child);
chrislovsund@177
  3346
                        }
chrislovsund@177
  3347
                    }
chrislovsund@177
  3348
                }
chrislovsund@177
  3349
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
  3350
                //only single comment line
chrislovsund@177
  3351
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
  3352
                    customStartToken = token;
chrislovsund@177
  3353
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
  3354
                    if (customStartToken != null) {
chrislovsund@177
  3355
                        String name = customStartToken.text().toString();
chrislovsund@177
  3356
                        int index = name.toUpperCase(Locale.ENGLISH).indexOf("<FOLD>");
chrislovsund@177
  3357
                        name = name.substring(index + 7).trim();
chrislovsund@177
  3358
                        if (ts.moveNext()) {
chrislovsund@177
  3359
                            token = ts.token();
chrislovsund@177
  3360
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@177
  3361
                                    token.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
  3362
                            customFoldBlocks.add(custom);
chrislovsund@177
  3363
                        }
chrislovsund@177
  3364
chrislovsund@177
  3365
                        customStartToken = null;
chrislovsund@177
  3366
                    }
chrislovsund@177
  3367
                } else {
chrislovsund@177
  3368
                    PlsqlBlock child = checkComment(token, ts);
chrislovsund@177
  3369
                    if (child != null) {
chrislovsund@177
  3370
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3371
                            lstChild.add(child);
chrislovsund@177
  3372
                        }
chrislovsund@177
  3373
                    }
chrislovsund@177
  3374
                }
chrislovsund@177
  3375
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@177
  3376
                int start = token.offset(tokenHierarchy);
chrislovsund@177
  3377
                PlsqlBlock child = new PlsqlBlock(start,
chrislovsund@177
  3378
                        start + token.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@177
  3379
                if (child != null) {
chrislovsund@177
  3380
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3381
                        lstChild.add(child);
chrislovsund@177
  3382
                    }
chrislovsund@177
  3383
                }
chrislovsund@177
  3384
            }
chrislovsund@177
  3385
chrislovsund@177
  3386
            moveNext = ts.moveNext();
chrislovsund@177
  3387
            token = ts.token();
chrislovsund@177
  3388
        }
chrislovsund@177
  3389
chrislovsund@177
  3390
        if (block != null) {
chrislovsund@177
  3391
            //add children
chrislovsund@177
  3392
            addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  3393
        } else {
chrislovsund@177
  3394
            if (moveNext) { //If have come to last return otherwise we will loop with begin
chrislovsund@177
  3395
                ts.move(declareBegin.offset(tokenHierarchy));
chrislovsund@177
  3396
                ts.moveNext();
chrislovsund@177
  3397
            }
chrislovsund@177
  3398
        }
chrislovsund@177
  3399
chrislovsund@177
  3400
        return block;
chrislovsund@177
  3401
    }
chrislovsund@177
  3402
chrislovsund@177
  3403
    /**
chrislovsund@177
  3404
     * Method that will check begin end blocks
chrislovsund@362
  3405
     *
chrislovsund@177
  3406
     * @param current
chrislovsund@177
  3407
     * @param ts
chrislovsund@177
  3408
     * @param parentBlocks
chrislovsund@177
  3409
     * @returns
chrislovsund@177
  3410
     */
chrislovsund@177
  3411
    private PlsqlBlock checkBeginBlock(Token<PlsqlTokenId> current, TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
  3412
        Token<PlsqlTokenId> begin;
chrislovsund@177
  3413
        Token<PlsqlTokenId> token = null;
chrislovsund@177
  3414
        PlsqlBlock block = null;
chrislovsund@177
  3415
        List<PlsqlBlock> lstChild = new ArrayList<PlsqlBlock>();
chrislovsund@177
  3416
        boolean moveNext = false;
chrislovsund@177
  3417
chrislovsund@177
  3418
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
  3419
        if (sqlPlusLine(ts)) {
chrislovsund@177
  3420
            return null;
chrislovsund@177
  3421
        }
chrislovsund@177
  3422
chrislovsund@177
  3423
        moveNext = ts.moveNext();
chrislovsund@177
  3424
        token = ts.token();
chrislovsund@177
  3425
        begin = current;
chrislovsund@177
  3426
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@177
  3427
chrislovsund@177
  3428
        while (moveNext) {
chrislovsund@177
  3429
            PlsqlTokenId tokenID = token.id();
chrislovsund@177
  3430
            String image = token.text().toString();
chrislovsund@177
  3431
chrislovsund@177
  3432
            if ((token != null) && (!image.equals(";")) && (token.offset(tokenHierarchy) > endParse)) {
chrislovsund@177
  3433
                break;
chrislovsund@177
  3434
            }
chrislovsund@177
  3435
chrislovsund@177
  3436
            //We have come to the end of the comment
chrislovsund@177
  3437
            if ((tokenID == PlsqlTokenId.OPERATOR) && ((image.equals("/") && checkForOnlyChar(ts, ts.offset())) || image.equals(";"))) {
chrislovsund@177
  3438
                //check whether its END; or END; before /
chrislovsund@177
  3439
                boolean movePre = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  3440
                Token<PlsqlTokenId> pre = ts.token();
chrislovsund@177
  3441
                if (!movePre) {
chrislovsund@177
  3442
                    ts.move(token.offset(tokenHierarchy));
chrislovsund@177
  3443
                    ts.moveNext();
chrislovsund@177
  3444
                }
chrislovsund@177
  3445
chrislovsund@177
  3446
                if (image.equals("/")) {
chrislovsund@177
  3447
                    if (pre.toString().equals(";")) {
chrislovsund@177
  3448
                        movePre = getPreviousNonWhitespace(ts, true);
chrislovsund@177
  3449
                        pre = ts.token();
chrislovsund@177
  3450
                        if ((movePre) && (pre.toString().equalsIgnoreCase("END"))) {
chrislovsund@177
  3451
                            //check whether there is a  DECLARE_END parent block with the same offset
chrislovsund@177
  3452
                            ts.move(token.offset(tokenHierarchy));
chrislovsund@177
  3453
                            ts.moveNext();
chrislovsund@177
  3454
                            ts.moveNext();
chrislovsund@177
  3455
                            int start = begin.offset(tokenHierarchy);
chrislovsund@177
  3456
                            int end = ts.offset();
chrislovsund@177
  3457
                            PlsqlBlock parent = getParentBlock(blockHierarchy, start, end);
chrislovsund@177
  3458
                            if ((parent == null) || (parent.getEndOffset() != end)) {
chrislovsund@177
  3459
                                block = new PlsqlBlock(start, end, "", "", PlsqlBlockType.BEGIN_END);
chrislovsund@177
  3460
                            }
chrislovsund@177
  3461
chrislovsund@177
  3462
                            break;
chrislovsund@177
  3463
chrislovsund@177
  3464
                        }
chrislovsund@177
  3465
                    } else {
chrislovsund@177
  3466
                        //something has gone wrong '/' is a terminal
chrislovsund@177
  3467
                        break;
chrislovsund@177
  3468
                    }
chrislovsund@177
  3469
                } else {
chrislovsund@177
  3470
                    if ((movePre) && (pre.toString().equalsIgnoreCase("END"))) {
chrislovsund@177
  3471
                        //check whether there is a  DECLARE_END parent block with the same offset
chrislovsund@177
  3472
                        ts.move(token.offset(tokenHierarchy));
chrislovsund@177
  3473
                        ts.moveNext();
chrislovsund@177
  3474
                        ts.moveNext();
chrislovsund@177
  3475
                        int start = begin.offset(tokenHierarchy);
chrislovsund@177
  3476
                        int end = ts.offset();
chrislovsund@177
  3477
                        PlsqlBlock parent = getParentBlock(blockHierarchy, start, end);
chrislovsund@177
  3478
                        if ((parent == null) || (parent.getEndOffset() != end)) {
chrislovsund@177
  3479
                            block = new PlsqlBlock(start, end, "", "", PlsqlBlockType.BEGIN_END);
chrislovsund@177
  3480
                        }
chrislovsund@177
  3481
chrislovsund@177
  3482
                        break;
chrislovsund@177
  3483
                    }
chrislovsund@177
  3484
                }
chrislovsund@177
  3485
                ts.move(token.offset(tokenHierarchy));
chrislovsund@177
  3486
                ts.moveNext();
chrislovsund@177
  3487
            } else if (tokenID == PlsqlTokenId.KEYWORD && image.equalsIgnoreCase("DECLARE")) {
chrislovsund@177
  3488
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3489
                PlsqlBlock child = checkDeclareBlock(token, ts, lstChild);
chrislovsund@177
  3490
                if (child != null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3491
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3492
                        lstChild.add(child);
chrislovsund@177
  3493
                    }
chrislovsund@177
  3494
                }
chrislovsund@177
  3495
            } else if (tokenID == PlsqlTokenId.KEYWORD && (image.equalsIgnoreCase("BEGIN"))) {
chrislovsund@177
  3496
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3497
                PlsqlBlock child = checkBeginBlock(token, ts, lstChild);
chrislovsund@177
  3498
                if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3499
chrislovsund@177
  3500
                    ts.move(beforeOff);
chrislovsund@177
  3501
                    moveNext = ts.moveNext();
chrislovsund@177
  3502
                } else {
chrislovsund@177
  3503
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3504
                        lstChild.add(child);
chrislovsund@177
  3505
                    }
chrislovsund@177
  3506
                }
chrislovsund@177
  3507
            } else if (image.equalsIgnoreCase("IF")) {
chrislovsund@177
  3508
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3509
                List children = checkIfBlock(token, ts, lstChild);
chrislovsund@177
  3510
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3511
chrislovsund@177
  3512
                    ts.move(beforeOff);
chrislovsund@177
  3513
                    moveNext = ts.moveNext();
chrislovsund@177
  3514
                } else {
chrislovsund@177
  3515
                    for (int i = 0; i < children.size(); i++) {
chrislovsund@177
  3516
                        PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@177
  3517
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3518
                            lstChild.add(child);
chrislovsund@177
  3519
                        }
chrislovsund@177
  3520
                    }
chrislovsund@177
  3521
                }
chrislovsund@177
  3522
            } else if (image.equalsIgnoreCase("CASE")) {
chrislovsund@177
  3523
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3524
                List children = checkCaseBlock(token, ts, lstChild, false);
chrislovsund@177
  3525
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3526
chrislovsund@177
  3527
                    ts.move(beforeOff);
chrislovsund@177
  3528
                    moveNext = ts.moveNext();
chrislovsund@177
  3529
                } else {
chrislovsund@177
  3530
                    for (int i = 0; i < children.size(); i++) {
chrislovsund@177
  3531
                        PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@177
  3532
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3533
                            lstChild.add(child);
chrislovsund@177
  3534
                        }
chrislovsund@177
  3535
                    }
chrislovsund@177
  3536
                }
chrislovsund@177
  3537
            } else if (image.equalsIgnoreCase("LOOP")
chrislovsund@177
  3538
                    || image.equalsIgnoreCase("WHILE")
chrislovsund@177
  3539
                    || image.equalsIgnoreCase("FOR")) {
chrislovsund@177
  3540
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  3541
                if (!unsuccessBlocks.contains(beforeOff)) {
chrislovsund@177
  3542
                    PlsqlBlock child = checkLoopBlock(token, ts, lstChild);
chrislovsund@177
  3543
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3544
                        unsuccessBlocks.add(beforeOff);
chrislovsund@177
  3545
                        ts.move(beforeOff);
chrislovsund@177
  3546
                        moveNext = ts.moveNext();
chrislovsund@177
  3547
                    } else {
chrislovsund@177
  3548
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3549
                            lstChild.add(child);
chrislovsund@177
  3550
                        }
chrislovsund@177
  3551
                    }
chrislovsund@177
  3552
                }
chrislovsund@177
  3553
            } else if (image.equalsIgnoreCase("TABLE")
chrislovsund@177
  3554
                    || image.equalsIgnoreCase("INDEX")
chrislovsund@177
  3555
                    || image.equalsIgnoreCase("SELECT")
chrislovsund@177
  3556
                    || image.equalsIgnoreCase("UPDATE")
chrislovsund@177
  3557
                    || image.equalsIgnoreCase("DELETE")
chrislovsund@177
  3558
                    || image.equalsIgnoreCase("INSERT")
chrislovsund@177
  3559
                    || image.equalsIgnoreCase("MERGE")
chrislovsund@177
  3560
                    || image.equalsIgnoreCase("DROP")
chrislovsund@177
  3561
                    || image.equalsIgnoreCase("SEQUENCE")) {
chrislovsund@177
  3562
                if (!isNotBlockStart(token, ts)) {
chrislovsund@177
  3563
                    int offset = token.offset(tokenHierarchy);
chrislovsund@177
  3564
                    PlsqlBlock child = checkStatementBlock(token, ts, parentBlocks);
chrislovsund@177
  3565
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  3566
chrislovsund@177
  3567
                        ts.move(offset);
chrislovsund@177
  3568
                        ts.moveNext();
chrislovsund@177
  3569
                    } else {
chrislovsund@177
  3570
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3571
                            lstChild.add(child);
chrislovsund@177
  3572
                        }
chrislovsund@177
  3573
                    }
chrislovsund@177
  3574
                }
chrislovsund@177
  3575
            } else if (image.equalsIgnoreCase("PROCEDURE")
chrislovsund@177
  3576
                    || image.equalsIgnoreCase("FUNCTION")) {
chrislovsund@177
  3577
                break;
chrislovsund@177
  3578
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
  3579
                //only single comment line
chrislovsund@177
  3580
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
  3581
                    customStartToken = token;
chrislovsund@177
  3582
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
  3583
                    if (customStartToken != null) {
chrislovsund@177
  3584
                        String name = customStartToken.text().toString();
chrislovsund@177
  3585
                        int index = name.toUpperCase(Locale.ENGLISH).indexOf("<FOLD>");
chrislovsund@177
  3586
                        name = name.substring(index + 7).trim();
chrislovsund@177
  3587
                        if (ts.moveNext()) {
chrislovsund@177
  3588
                            token = ts.token();
chrislovsund@177
  3589
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@177
  3590
                                    token.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
  3591
                            customFoldBlocks.add(custom);
chrislovsund@177
  3592
                        }
chrislovsund@177
  3593
chrislovsund@177
  3594
                        customStartToken = null;
chrislovsund@177
  3595
                    }
chrislovsund@177
  3596
                } else {
chrislovsund@177
  3597
                    PlsqlBlock child = checkComment(token, ts);
chrislovsund@177
  3598
                    if (child != null) {
chrislovsund@177
  3599
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3600
                            lstChild.add(child);
chrislovsund@177
  3601
                        }
chrislovsund@177
  3602
                    }
chrislovsund@177
  3603
                }
chrislovsund@177
  3604
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@177
  3605
                int start = token.offset(tokenHierarchy);
chrislovsund@177
  3606
                PlsqlBlock child = new PlsqlBlock(start,
chrislovsund@177
  3607
                        start + token.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@177
  3608
                if (child != null) {
chrislovsund@177
  3609
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3610
                        lstChild.add(child);
chrislovsund@177
  3611
                    }
chrislovsund@177
  3612
                }
chrislovsund@177
  3613
            }
chrislovsund@177
  3614
chrislovsund@177
  3615
            moveNext = ts.moveNext();
chrislovsund@177
  3616
            token = ts.token();
chrislovsund@177
  3617
        }
chrislovsund@177
  3618
chrislovsund@177
  3619
        if (block != null) {
chrislovsund@177
  3620
            //add children
chrislovsund@177
  3621
            addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  3622
        }
chrislovsund@177
  3623
chrislovsund@177
  3624
        return block;
chrislovsund@177
  3625
    }
chrislovsund@177
  3626
chrislovsund@177
  3627
    /**
chrislovsund@177
  3628
     * Method to check table & column comments
chrislovsund@362
  3629
     *
chrislovsund@177
  3630
     * @param current
chrislovsund@177
  3631
     * @param ts
chrislovsund@177
  3632
     * @param parentBlocks
chrislovsund@177
  3633
     * @returns
chrislovsund@177
  3634
     */
chrislovsund@177
  3635
    private PlsqlBlock checkTblColComment(Token<PlsqlTokenId> current, TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
  3636
        Token<PlsqlTokenId> commentBegin = current;
chrislovsund@177
  3637
        Token<PlsqlTokenId> tmpPre = current;
chrislovsund@177
  3638
        PlsqlBlock block = null;
chrislovsund@177
  3639
        List<PlsqlBlock> lstChild = new ArrayList<PlsqlBlock>();
chrislovsund@177
  3640
chrislovsund@177
  3641
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
  3642
        if (sqlPlusLine(ts)) {
chrislovsund@177
  3643
            return null;
chrislovsund@177
  3644
        }
chrislovsund@177
  3645
chrislovsund@177
  3646
        int beginOffset = ts.offset();
chrislovsund@177
  3647
        boolean isTable = false;
chrislovsund@177
  3648
        boolean isEnd = false;
chrislovsund@177
  3649
        Token<PlsqlTokenId> previousBlock = null;
chrislovsund@177
  3650
        String tableName = "";
chrislovsund@177
  3651
        boolean moveNext = false;
chrislovsund@177
  3652
        moveNext = getNextNonWhitespace(ts, true);
chrislovsund@177
  3653
        String alias = "";
chrislovsund@177
  3654
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@177
  3655
chrislovsund@177
  3656
        //Check whether that is table/column comment
chrislovsund@177
  3657
        if (moveNext == false) {
chrislovsund@177
  3658
            return block;
chrislovsund@177
  3659
        }
chrislovsund@177
  3660
chrislovsund@177
  3661
        Token<PlsqlTokenId> tmp = ts.token(); //catching ON
chrislovsund@177
  3662
chrislovsund@177
  3663
        moveNext = getNextNonWhitespace(ts, true);
chrislovsund@177
  3664
        tmp = ts.token();    //TABLE OR VIEW
chrislovsund@177
  3665
chrislovsund@177
  3666
        if ((moveNext != false) && (tmp.id() == PlsqlTokenId.KEYWORD)) {
chrislovsund@177
  3667
            String image = tmp.text().toString();
chrislovsund@177
  3668
            if (image.equalsIgnoreCase("TABLE")) {
chrislovsund@177
  3669
                isTable = true;
chrislovsund@177
  3670
chrislovsund@177
  3671
                moveNext = getNextNonWhitespace(ts, true);
chrislovsund@177
  3672
                tmp = ts.token();
chrislovsund@177
  3673
chrislovsund@177
  3674
                if (moveNext != false) {
chrislovsund@177
  3675
                    tableName = tmp.text().toString();
chrislovsund@177
  3676
                    tableName = checkForOtherSchema(ts, tableName);
chrislovsund@177
  3677
                    if (tableName.indexOf('&') != -1) {
chrislovsund@177
  3678
                        alias = tableName;
chrislovsund@177
  3679
                    }
chrislovsund@177
  3680
chrislovsund@177
  3681
                    tableName = getDefine(tableName);
chrislovsund@177
  3682
                    if (ts.moveNext()) {
chrislovsund@177
  3683
                        tmp = ts.token();
chrislovsund@177
  3684
                        if ((tmp.id() == PlsqlTokenId.DOT) && ts.moveNext()) {
chrislovsund@177
  3685
                            tmp = ts.token();
chrislovsund@177
  3686
                        }
chrislovsund@177
  3687
                    }
chrislovsund@177
  3688
                }
chrislovsund@177
  3689
chrislovsund@177
  3690
            } else if (image.equalsIgnoreCase("COLUMN")) {
chrislovsund@177
  3691
                isTable = false;
chrislovsund@177
  3692
                moveNext = getNextNonWhitespace(ts, true);
chrislovsund@177
  3693
                tmp = ts.token();
chrislovsund@177
  3694
chrislovsund@177
  3695
                if (moveNext != false) {
chrislovsund@177
  3696
                    tableName = tmp.text().toString();
chrislovsund@177
  3697
                    if (tableName.indexOf('&') != -1) {
chrislovsund@177
  3698
                        alias = tableName;
chrislovsund@177
  3699
                    }
chrislovsund@177
  3700
chrislovsund@177
  3701
                    tableName = getDefine(tableName);
chrislovsund@177
  3702
                    if (ts.moveNext()) {
chrislovsund@177
  3703
                        tmp = ts.token();
chrislovsund@177
  3704
                        if ((tmp.id() == PlsqlTokenId.DOT) && ts.moveNext()) {
chrislovsund@177
  3705
                            tmp = ts.token();
chrislovsund@177
  3706
                        }
chrislovsund@177
  3707
                    }
chrislovsund@177
  3708
                }
chrislovsund@177
  3709
            } else {
chrislovsund@177
  3710
                ts.move(beginOffset);
chrislovsund@177
  3711
                ts.moveNext();
chrislovsund@177
  3712
                ts.moveNext();
chrislovsund@177
  3713
                return block;
chrislovsund@177
  3714
            }
chrislovsund@177
  3715
        }
chrislovsund@177
  3716
chrislovsund@177
  3717
        while (moveNext) {
chrislovsund@177
  3718
            PlsqlTokenId tokenID = tmp.id();
chrislovsund@177
  3719
            String image = tmp.text().toString();
chrislovsund@177
  3720
chrislovsund@177
  3721
            //Check end offset and break (exception for colun which will mark end of some blocks)
chrislovsund@177
  3722
            if ((tmp != null) && (tmp.offset(tokenHierarchy) > endParse) && (!image.equals(";")) && (!(image.equals("/") && checkForOnlyChar(ts, ts.offset())))) {
chrislovsund@177
  3723
                ts.move(beginOffset);
chrislovsund@177
  3724
                ts.moveNext();
chrislovsund@177
  3725
                ts.moveNext();
chrislovsund@177
  3726
                break;
chrislovsund@177
  3727
            }
chrislovsund@177
  3728
chrislovsund@177
  3729
            //We have come to the end of the comment
chrislovsund@177
  3730
            if ((tokenID == PlsqlTokenId.OPERATOR)
chrislovsund@177
  3731
                    && (image.equals(";") || (image.equals("/") && checkForOnlyChar(ts, ts.offset())))) {
chrislovsund@177
  3732
                isEnd = true;
chrislovsund@177
  3733
                previousBlock = tmp;
chrislovsund@177
  3734
                int offset = ts.offset();
chrislovsund@177
  3735
                boolean mNext = getNextNonWhitespace(ts, false); //after ';' dont ignore comments
chrislovsund@177
  3736
chrislovsund@177
  3737
                Token<PlsqlTokenId> next = ts.token();
chrislovsund@177
  3738
                ts.move(offset);
chrislovsund@177
  3739
                ts.moveNext();
chrislovsund@177
  3740
chrislovsund@177
  3741
                if ((mNext == false) || (!next.text().toString().equalsIgnoreCase("COMMENT"))
chrislovsund@177
  3742
                        || ((next.text().toString().equalsIgnoreCase("COMMENT")) && (next.offset(tokenHierarchy) > endParse))) {                  //we have come to the end of the comments
chrislovsund@177
  3743
chrislovsund@177
  3744
                    if (isTable) {
chrislovsund@177
  3745
                        block = new PlsqlBlock(commentBegin.offset(tokenHierarchy),
chrislovsund@177
  3746
                                previousBlock.offset(tokenHierarchy), tableName, alias, PlsqlBlockType.TABLE_COMMENT);
chrislovsund@177
  3747
                    } else {
chrislovsund@177
  3748
                        block = new PlsqlBlock(commentBegin.offset(tokenHierarchy),
chrislovsund@177
  3749
                                previousBlock.offset(tokenHierarchy), tableName, alias, PlsqlBlockType.COLUMN_COMMENT);
chrislovsund@177
  3750
                    }
chrislovsund@177
  3751
chrislovsund@177
  3752
                    break;
chrislovsund@177
  3753
                }
chrislovsund@177
  3754
            } else if ((tokenID == PlsqlTokenId.KEYWORD)) {
chrislovsund@177
  3755
                if (image.equalsIgnoreCase("COLUMN")) {
chrislovsund@177
  3756
                    if (isTable == true) {
chrislovsund@177
  3757
                        isTable = false;
chrislovsund@177
  3758
chrislovsund@177
  3759
                        if (previousBlock != null) {
chrislovsund@177
  3760
                            //Create table comment fold
chrislovsund@177
  3761
                            block = new PlsqlBlock(commentBegin.offset(tokenHierarchy),
chrislovsund@177
  3762
                                    previousBlock.offset(tokenHierarchy), tableName, alias, PlsqlBlockType.TABLE_COMMENT);
chrislovsund@177
  3763
                            ts.move(tmpPre.offset(tokenHierarchy));
chrislovsund@177
  3764
                            break;
chrislovsund@177
  3765
                        }
chrislovsund@177
  3766
                    }
chrislovsund@177
  3767
                } else if (image.equalsIgnoreCase("TABLE")) {
chrislovsund@177
  3768
                    if (isTable == false) {
chrislovsund@177
  3769
                        isTable = true;
chrislovsund@177
  3770
chrislovsund@177
  3771
                        if (previousBlock != null) {
chrislovsund@177
  3772
                            //Create column comment fold
chrislovsund@177
  3773
                            block = new PlsqlBlock(commentBegin.offset(tokenHierarchy),
chrislovsund@177
  3774
                                    previousBlock.offset(tokenHierarchy), tableName, alias, PlsqlBlockType.COLUMN_COMMENT);
chrislovsund@177
  3775
                            ts.move(tmpPre.offset(tokenHierarchy));
chrislovsund@177
  3776
                            break;
chrislovsund@177
  3777
                        }
chrislovsund@177
  3778
                    }
chrislovsund@177
  3779
                } else if (image.equalsIgnoreCase("COMMENT")) {
chrislovsund@177
  3780
                    tmpPre = tmp;
chrislovsund@177
  3781
                    moveNext = getNextNonWhitespace(ts, true);
chrislovsund@177
  3782
                    tmp = ts.token();
chrislovsund@177
  3783
                    if (isEnd == false) {
chrislovsund@177
  3784
                        commentBegin = tmpPre;
chrislovsund@177
  3785
                    }
chrislovsund@177
  3786
                }
chrislovsund@177
  3787
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
  3788
                //only single comment line
chrislovsund@177
  3789
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
  3790
                    customStartToken = tmp;
chrislovsund@177
  3791
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
  3792
                    if (customStartToken != null) {
chrislovsund@177
  3793
                        String name = customStartToken.text().toString();
chrislovsund@177
  3794
                        int index = name.toUpperCase(Locale.ENGLISH).indexOf("<FOLD>");
chrislovsund@177
  3795
                        name = name.substring(index + 7).trim();
chrislovsund@177
  3796
                        if (ts.moveNext()) {
chrislovsund@177
  3797
                            tmp = ts.token();
chrislovsund@177
  3798
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@177
  3799
                                    tmp.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
  3800
                            customFoldBlocks.add(custom);
chrislovsund@177
  3801
                        }
chrislovsund@177
  3802
chrislovsund@177
  3803
                        customStartToken = null;
chrislovsund@177
  3804
                    }
chrislovsund@177
  3805
                } else {
chrislovsund@177
  3806
                    PlsqlBlock child = checkComment(tmp, ts);
chrislovsund@177
  3807
                    if (child != null) {
chrislovsund@177
  3808
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3809
                            lstChild.add(child);
chrislovsund@177
  3810
                        }
chrislovsund@177
  3811
                    }
chrislovsund@177
  3812
                }
chrislovsund@177
  3813
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@177
  3814
                int start = tmp.offset(tokenHierarchy);
chrislovsund@177
  3815
                PlsqlBlock child = new PlsqlBlock(start,
chrislovsund@177
  3816
                        start + tmp.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@177
  3817
                if (child != null) {
chrislovsund@177
  3818
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  3819
                        lstChild.add(child);
chrislovsund@177
  3820
                    }
chrislovsund@177
  3821
                }
chrislovsund@177
  3822
            }
chrislovsund@177
  3823
jrechtacek@0
  3824
            moveNext = getNextNonWhitespace(ts, true);
jrechtacek@0
  3825
            tmp = ts.token();
chrislovsund@177
  3826
        }
chrislovsund@177
  3827
chrislovsund@177
  3828
        if (block != null) {
chrislovsund@177
  3829
            //add children
chrislovsund@177
  3830
            addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  3831
        }
chrislovsund@177
  3832
chrislovsund@177
  3833
        return block;
chrislovsund@177
  3834
    }
chrislovsund@177
  3835
chrislovsund@177
  3836
    /**
chrislovsund@177
  3837
     * Get Return next non whitespace token
chrislovsund@362
  3838
     *
chrislovsund@177
  3839
     * @param ts
chrislovsund@177
  3840
     * @param ignoreComment: if true will ignore comments also
chrislovsund@177
  3841
     * @return
chrislovsund@177
  3842
     */
chrislovsund@177
  3843
    private boolean getNextNonWhitespace(TokenSequence<PlsqlTokenId> ts, boolean ignoreComment) {
chrislovsund@177
  3844
        boolean moveNext = ts.moveNext();
chrislovsund@177
  3845
        Token<PlsqlTokenId> tmp = ts.token();
chrislovsund@177
  3846
chrislovsund@177
  3847
chrislovsund@177
  3848
        while (moveNext) {
chrislovsund@177
  3849
            if (tmp.id() == PlsqlTokenId.WHITESPACE) {
chrislovsund@177
  3850
                moveNext = ts.moveNext();
chrislovsund@177
  3851
                tmp = ts.token();
chrislovsund@177
  3852
            } else {
chrislovsund@177
  3853
                if ((ignoreComment == true) && (tmp.id() == PlsqlTokenId.LINE_COMMENT
chrislovsund@177
  3854
                        || tmp.id() == PlsqlTokenId.BLOCK_COMMENT)) {
chrislovsund@177
  3855
                    moveNext = ts.moveNext();
chrislovsund@177
  3856
                    tmp = ts.token();
chrislovsund@177
  3857
                } else {
chrislovsund@177
  3858
                    break;
chrislovsund@177
  3859
                }
jrechtacek@0
  3860
            }
chrislovsund@177
  3861
        }
chrislovsund@177
  3862
chrislovsund@177
  3863
        return moveNext;
chrislovsund@177
  3864
    }
chrislovsund@177
  3865
chrislovsund@177
  3866
    /**
chrislovsund@362
  3867
     * Get Return next non whitespace token
chrislovsund@362
  3868
     *
chrislovsund@362
  3869
     * @param ts
chrislovsund@362
  3870
     * @return
chrislovsund@362
  3871
     */
chrislovsund@362
  3872
    private boolean getNextNonWhitespaceForComments(TokenSequence<PlsqlTokenId> ts) {
chrislovsund@362
  3873
        boolean moveNext = ts.moveNext();
chrislovsund@362
  3874
        Token<PlsqlTokenId> tmp = ts.token();
chrislovsund@362
  3875
        LOG.log(Level.FINE, "getNextNonWhitespaceForComments, tmp.id()={0}, tmp.text()={1}", new Object[]{tmp.id(), tmp.text().toString()});
chrislovsund@362
  3876
        while (moveNext) {
subslk@464
  3877
            if (tmp.id() == PlsqlTokenId.WHITESPACE && ("\n".equals(tmp.text()) || tmp.text().toString().contains("\n "))) {
chrislovsund@362
  3878
                moveNext = ts.moveNext();
chrislovsund@362
  3879
                tmp = ts.token();
chrislovsund@362
  3880
            } else {
chrislovsund@362
  3881
                break;
chrislovsund@362
  3882
            }
chrislovsund@362
  3883
        }
chrislovsund@362
  3884
        return moveNext;
chrislovsund@362
  3885
    }
chrislovsund@362
  3886
chrislovsund@362
  3887
    /**
chrislovsund@177
  3888
     * Return previous non whitespace token
chrislovsund@362
  3889
     *
chrislovsund@177
  3890
     * @param ts
chrislovsund@177
  3891
     * @param ignoreComment
chrislovsund@177
  3892
     * @return
chrislovsund@177
  3893
     */
chrislovsund@177
  3894
    private boolean getPreviousNonWhitespace(TokenSequence<PlsqlTokenId> ts, boolean ignoreComment) {
chrislovsund@177
  3895
        boolean movePrevious = ts.movePrevious();
chrislovsund@177
  3896
        Token<PlsqlTokenId> tmp = ts.token();
chrislovsund@177
  3897
chrislovsund@177
  3898
        while (movePrevious) {
chrislovsund@177
  3899
            if (tmp.id() == PlsqlTokenId.WHITESPACE) {
chrislovsund@177
  3900
                movePrevious = ts.movePrevious();
chrislovsund@177
  3901
                tmp = ts.token();
chrislovsund@177
  3902
            } else {
chrislovsund@177
  3903
                if ((ignoreComment == true) && (tmp.id() == PlsqlTokenId.LINE_COMMENT
chrislovsund@177
  3904
                        || tmp.id() == PlsqlTokenId.BLOCK_COMMENT)) {
chrislovsund@177
  3905
                    movePrevious = ts.movePrevious();
chrislovsund@177
  3906
                    tmp = ts.token();
chrislovsund@177
  3907
                } else {
chrislovsund@177
  3908
                    break;
chrislovsund@177
  3909
                }
chrislovsund@177
  3910
            }
chrislovsund@177
  3911
        }
chrislovsund@177
  3912
        return movePrevious;
chrislovsund@177
  3913
    }
chrislovsund@177
  3914
chrislovsund@177
  3915
    /**
chrislovsund@177
  3916
     * Check whether this is the start of a VIEW block
chrislovsund@362
  3917
     *
chrislovsund@177
  3918
     * @param viewToken
chrislovsund@177
  3919
     * @param ts
chrislovsund@177
  3920
     * @param parentBlocks
chrislovsund@177
  3921
     * @return
chrislovsund@177
  3922
     */
chrislovsund@177
  3923
    private PlsqlBlock checkView(Token<PlsqlTokenId> viewToken, TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
  3924
        Token<PlsqlTokenId> viewBegin = viewToken;
chrislovsund@177
  3925
        Token<PlsqlTokenId> tmp = viewToken;
chrislovsund@177
  3926
        PlsqlBlock block = null;
chrislovsund@177
  3927
        List<PlsqlBlock> lstChild = new ArrayList<PlsqlBlock>();
chrislovsund@177
  3928
chrislovsund@177
  3929
        boolean moveNext = false;
chrislovsund@177
  3930
        String viewName = "";
chrislovsund@177
  3931
        int offset = ts.offset();
chrislovsund@177
  3932
chrislovsund@177
  3933
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
  3934
        if (sqlPlusLine(ts)) {
chrislovsund@177
  3935
            return null;
chrislovsund@177
  3936
        }
chrislovsund@177
  3937
chrislovsund@177
  3938
        //second non whitespace character should be the name
chrislovsund@177
  3939
        moveNext = getNextNonWhitespace(ts, true);
chrislovsund@177
  3940
        if (moveNext == false) {
chrislovsund@177
  3941
            ts.move(offset);
jrechtacek@0
  3942
            ts.moveNext();
jrechtacek@0
  3943
            return block;
chrislovsund@177
  3944
        }
chrislovsund@177
  3945
chrislovsund@177
  3946
        tmp = ts.token();
chrislovsund@177
  3947
chrislovsund@177
  3948
        //Second token is the view name
chrislovsund@177
  3949
        viewName = tmp.text().toString().trim();
chrislovsund@177
  3950
        viewName = checkForOtherSchema(ts, viewName);
chrislovsund@177
  3951
        String alias = "";
chrislovsund@177
  3952
        if (viewName.indexOf('&') != -1) {
chrislovsund@177
  3953
            alias = viewName;
chrislovsund@177
  3954
            viewName = getDefine(viewName);
chrislovsund@177
  3955
        }
jrechtacek@0
  3956
//      if (ts.moveNext()) {
jrechtacek@0
  3957
//         tmp = ts.token();
jrechtacek@0
  3958
//         if ((tmp.id() == PlsqlTokenId.DOT) && ts.moveNext()) {
jrechtacek@0
  3959
//            tmp = ts.token();
jrechtacek@0
  3960
//            viewName = viewName + "." + tmp.toString();
jrechtacek@0
  3961
//
jrechtacek@0
  3962
//            //Move to next token
jrechtacek@0
  3963
//            moveNext = getNextNonWhitespace(ts, true);
jrechtacek@0
  3964
//            tmp = ts.token();
jrechtacek@0
  3965
//         }
jrechtacek@0
  3966
//      }
jrechtacek@0
  3967
chrislovsund@177
  3968
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@177
  3969
        boolean isOk = false;
chrislovsund@177
  3970
chrislovsund@177
  3971
        while (moveNext) {
chrislovsund@177
  3972
            String image = tmp.text().toString();
chrislovsund@177
  3973
            PlsqlTokenId tokenID = tmp.id();
chrislovsund@177
  3974
chrislovsund@177
  3975
            //Check end offset and break(exception for colun which will mark end of some blocks)
chrislovsund@177
  3976
            if ((tmp != null) && (tmp.offset(tokenHierarchy) > endParse) && (!image.equals(";"))) {
chrislovsund@177
  3977
                break;
chrislovsund@177
  3978
            }
chrislovsund@177
  3979
chrislovsund@177
  3980
            if ((tokenID == PlsqlTokenId.KEYWORD) && (image.equalsIgnoreCase("AS"))) {
chrislovsund@177
  3981
                isOk = true;
chrislovsund@177
  3982
            }
chrislovsund@177
  3983
chrislovsund@177
  3984
            //We have come to the end of the view declaration
chrislovsund@177
  3985
            if ((tokenID == PlsqlTokenId.OPERATOR)
chrislovsund@177
  3986
                    && (image.equals(";") || (image.equals("/") && checkForOnlyChar(ts, ts.offset())))) {
chrislovsund@177
  3987
                if (isOk) {
jrechtacek@0
  3988
//               String alias = "";
jrechtacek@0
  3989
//               if (viewName.indexOf('&') != -1) {
jrechtacek@0
  3990
//                  int dotIndex = viewName.indexOf('.');
jrechtacek@0
  3991
//                  if (dotIndex != -1) {
jrechtacek@0
  3992
//                     String firstPart = viewName.substring(0, dotIndex);
jrechtacek@0
  3993
//                     alias = firstPart;
jrechtacek@0
  3994
//                     viewName = getDefine(firstPart) + viewName.substring(dotIndex + 1);
jrechtacek@0
  3995
//                  } else {
jrechtacek@0
  3996
//                     alias = viewName;
jrechtacek@0
  3997
//                     viewName = getDefine(viewName);
jrechtacek@0
  3998
//                  }
jrechtacek@0
  3999
//               }
jrechtacek@0
  4000
chrislovsund@177
  4001
                    block = new PlsqlBlock(viewBegin.offset(tokenHierarchy),
chrislovsund@177
  4002
                            tmp.offset(tokenHierarchy), viewName, alias, PlsqlBlockType.VIEW);
chrislovsund@177
  4003
                    checkPrefix(viewBegin.offset(tokenHierarchy), ts, block);
chrislovsund@177
  4004
                    break;
chrislovsund@177
  4005
                } else {
chrislovsund@177
  4006
                    ts.move(offset);
chrislovsund@177
  4007
                    ts.moveNext();
chrislovsund@177
  4008
                    ts.moveNext(); // to avoid getting caught here again we have to move next
chrislovsund@177
  4009
                    break;
chrislovsund@177
  4010
                }
chrislovsund@177
  4011
            } else if ((tokenID == PlsqlTokenId.KEYWORD)
chrislovsund@177
  4012
                    && ((image.equalsIgnoreCase("COMMENT"))
chrislovsund@177
  4013
                    || (image.equalsIgnoreCase("CREATE")))) { //Avoid catching ';' of other statements
chrislovsund@177
  4014
chrislovsund@177
  4015
                ts.move(offset);
chrislovsund@177
  4016
                ts.moveNext();
chrislovsund@177
  4017
                ts.moveNext(); // to avoid getting caught here again we have to move next
chrislovsund@177
  4018
chrislovsund@177
  4019
                break;
chrislovsund@177
  4020
chrislovsund@177
  4021
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
  4022
                //only single comment line
chrislovsund@177
  4023
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
  4024
                    customStartToken = tmp;
chrislovsund@177
  4025
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
  4026
                    if (customStartToken != null) {
chrislovsund@177
  4027
                        String name = customStartToken.text().toString();
chrislovsund@177
  4028
                        int index = name.toUpperCase(Locale.ENGLISH).indexOf("<FOLD>");
chrislovsund@177
  4029
                        name = name.substring(index + 7).trim();
chrislovsund@177
  4030
                        if (ts.moveNext()) {
chrislovsund@177
  4031
                            tmp = ts.token();
chrislovsund@177
  4032
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@177
  4033
                                    tmp.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
  4034
                            customFoldBlocks.add(custom);
chrislovsund@177
  4035
                        }
chrislovsund@177
  4036
chrislovsund@177
  4037
                        customStartToken = null;
chrislovsund@177
  4038
                    }
chrislovsund@177
  4039
                } else {
chrislovsund@177
  4040
                    PlsqlBlock child = checkComment(tmp, ts);
chrislovsund@177
  4041
                    if (child != null) {
chrislovsund@177
  4042
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4043
                            lstChild.add(child);
chrislovsund@177
  4044
                        }
chrislovsund@177
  4045
                    }
chrislovsund@177
  4046
                }
chrislovsund@177
  4047
                moveNext = ts.moveNext();
chrislovsund@177
  4048
                tmp = ts.token();
chrislovsund@177
  4049
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@177
  4050
                int start = tmp.offset(tokenHierarchy);
chrislovsund@177
  4051
                PlsqlBlock child = new PlsqlBlock(start,
chrislovsund@177
  4052
                        start + tmp.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@177
  4053
                if (child != null) {
chrislovsund@177
  4054
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4055
                        lstChild.add(child);
chrislovsund@177
  4056
                    }
chrislovsund@177
  4057
                }
chrislovsund@177
  4058
                moveNext = ts.moveNext();
chrislovsund@177
  4059
                tmp = ts.token();
jrechtacek@0
  4060
            } else {
chrislovsund@177
  4061
                moveNext = ts.moveNext();
chrislovsund@177
  4062
                tmp = ts.token();
jrechtacek@0
  4063
            }
chrislovsund@177
  4064
        }
chrislovsund@177
  4065
chrislovsund@177
  4066
        if (block != null) {
chrislovsund@177
  4067
            //add children
chrislovsund@177
  4068
            addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  4069
        }
chrislovsund@177
  4070
chrislovsund@177
  4071
        return block;
chrislovsund@177
  4072
    }
chrislovsund@177
  4073
chrislovsund@177
  4074
    /**
chrislovsund@177
  4075
     * Get the name defined by &Name
chrislovsund@362
  4076
     *
chrislovsund@177
  4077
     * @param inputName
chrislovsund@177
  4078
     * @return
chrislovsund@177
  4079
     */
chrislovsund@177
  4080
    public String getDefine(
chrislovsund@177
  4081
            String inputName) {
chrislovsund@177
  4082
        String name = inputName;
chrislovsund@177
  4083
chrislovsund@177
  4084
        if (name.indexOf('&', 0) != -1) {
chrislovsund@177
  4085
            String val = definesMap.get(name.substring(1).toUpperCase(Locale.ENGLISH));
chrislovsund@177
  4086
            if (val != null) {
chrislovsund@177
  4087
                name = val;
jrechtacek@0
  4088
            }
chrislovsund@177
  4089
        }
chrislovsund@177
  4090
chrislovsund@177
  4091
        return name;
chrislovsund@177
  4092
    }
chrislovsund@177
  4093
chrislovsund@177
  4094
    /**
chrislovsund@177
  4095
     * Check &Name is in map as a key
chrislovsund@362
  4096
     *
chrislovsund@177
  4097
     * @param inputName
chrislovsund@177
  4098
     * @return
chrislovsund@177
  4099
     */
chrislovsund@177
  4100
    public boolean isDefine(String inputName) {
chrislovsund@177
  4101
        String name = inputName;
chrislovsund@177
  4102
chrislovsund@177
  4103
        if (name.indexOf('&', 0) != -1) {
chrislovsund@177
  4104
            return definesMap.containsKey(name.substring(1).toUpperCase(Locale.ENGLISH));
chrislovsund@177
  4105
        }
chrislovsund@177
  4106
chrislovsund@177
  4107
        return false;
chrislovsund@177
  4108
    }
chrislovsund@177
  4109
chrislovsund@177
  4110
    /**
chrislovsund@177
  4111
     * Check &Name is in map as a value
chrislovsund@362
  4112
     *
chrislovsund@177
  4113
     * @param inputName
chrislovsund@177
  4114
     * @return
chrislovsund@177
  4115
     */
chrislovsund@177
  4116
    public boolean hasDefineKey(String inputName) {
chrislovsund@177
  4117
        String name = inputName;
chrislovsund@177
  4118
        return definesMap.containsValue(name.toUpperCase(Locale.ENGLISH));
chrislovsund@177
  4119
    }
chrislovsund@177
  4120
chrislovsund@177
  4121
    /**
chrislovsund@177
  4122
     * Get the key of &Name
chrislovsund@362
  4123
     *
chrislovsund@177
  4124
     * @param inputName
chrislovsund@177
  4125
     * @return
chrislovsund@177
  4126
     */
chrislovsund@177
  4127
    public String getDefineKey(String inputName) {
chrislovsund@177
  4128
        for (Object o : definesMap.keySet()) {
chrislovsund@177
  4129
            if (definesMap.get(o).equals(inputName)) {
chrislovsund@177
  4130
                return o.toString();
chrislovsund@177
  4131
            }
chrislovsund@177
  4132
        }
chrislovsund@177
  4133
        return null;
chrislovsund@177
  4134
    }
chrislovsund@177
  4135
chrislovsund@177
  4136
    public Map<String, String> getDefines() {
chrislovsund@177
  4137
        return Collections.unmodifiableMap(definesMap);
chrislovsund@177
  4138
    }
chrislovsund@177
  4139
chrislovsund@177
  4140
    /**
chrislovsund@177
  4141
     * Method that will parse the document and initialize the aliases
chrislovsund@362
  4142
     *
chrislovsund@177
  4143
     * @param doc
chrislovsund@177
  4144
     */
chrislovsund@177
  4145
    private void getAliases(Document doc) {
chrislovsund@177
  4146
        TokenHierarchy tokenHier = TokenHierarchy.get(doc);
chrislovsund@177
  4147
        @SuppressWarnings("unchecked")
chrislovsund@177
  4148
        TokenSequence<PlsqlTokenId> ts = tokenHier.tokenSequence(PlsqlTokenId.language());
chrislovsund@177
  4149
        if (ts == null) {
chrislovsund@177
  4150
            return;
chrislovsund@177
  4151
        }
chrislovsund@177
  4152
chrislovsund@177
  4153
        //start to check aliases from the previous line end
chrislovsund@177
  4154
        ts.move(startParse);
chrislovsund@177
  4155
        Token<PlsqlTokenId> token = ts.token();
chrislovsund@177
  4156
chrislovsund@177
  4157
        //Get the difine by the name
chrislovsund@177
  4158
        while (ts.moveNext() && ts.offset() <= endParse) {
chrislovsund@177
  4159
            token = ts.token();
chrislovsund@177
  4160
            //Check whether this is DEFINE
chrislovsund@177
  4161
            if (token.id() == PlsqlTokenId.SQL_PLUS
chrislovsund@177
  4162
                    && (token.toString().equalsIgnoreCase("DEF")
chrislovsund@177
  4163
                    || token.toString().equalsIgnoreCase("DEFI")
chrislovsund@177
  4164
                    || token.toString().equalsIgnoreCase("DEFIN")
chrislovsund@177
  4165
                    || token.toString().equalsIgnoreCase("DEFINE"))) {
chrislovsund@177
  4166
                String tokenTxt = readLine(ts, token);
chrislovsund@177
  4167
                if (!tokenTxt.contains(" = ") && tokenTxt.contains("=")) {
chrislovsund@177
  4168
                    tokenTxt = tokenTxt.substring(0, tokenTxt.indexOf("=")) + " = " + tokenTxt.substring(tokenTxt.indexOf("=") + 1);
chrislovsund@177
  4169
                }
chrislovsund@177
  4170
chrislovsund@177
  4171
                StringTokenizer tokenizer = new StringTokenizer(tokenTxt);
chrislovsund@177
  4172
                tokenizer.nextToken();
chrislovsund@177
  4173
                String alias;
chrislovsund@177
  4174
                String value = "";
chrislovsund@177
  4175
                boolean isNext = tokenizer.hasMoreTokens();
chrislovsund@177
  4176
chrislovsund@177
  4177
                //alias
chrislovsund@177
  4178
                if (isNext) {
chrislovsund@177
  4179
                    alias = tokenizer.nextToken();
chrislovsund@177
  4180
                } else {
chrislovsund@177
  4181
                    break;
chrislovsund@177
  4182
                }
chrislovsund@177
  4183
chrislovsund@177
  4184
                isNext = tokenizer.hasMoreTokens();
chrislovsund@177
  4185
chrislovsund@177
  4186
                if ((isNext) && (tokenizer.nextToken().equals("="))) {
chrislovsund@177
  4187
                    boolean isComment = false;
chrislovsund@177
  4188
                    while (tokenizer.hasMoreTokens() && !isComment) {
chrislovsund@177
  4189
                        String temp = tokenizer.nextToken();
chrislovsund@177
  4190
                        if (temp.startsWith("--") || temp.startsWith("/*")) {
chrislovsund@177
  4191
                            isComment = true;
chrislovsund@177
  4192
                        } else {
chrislovsund@177
  4193
                            value = value + " " + temp;
chrislovsund@177
  4194
                        }
chrislovsund@177
  4195
                    }
chrislovsund@177
  4196
chrislovsund@177
  4197
                    value = value.trim();
chrislovsund@177
  4198
chrislovsund@177
  4199
                    if ((value.startsWith("\"") && value.endsWith("\""))
chrislovsund@177
  4200
                            || (value.startsWith("\'") && value.endsWith("\'"))) {
chrislovsund@177
  4201
                        value = value.substring(1, value.length() - 1);
chrislovsund@177
  4202
                    }
chrislovsund@177
  4203
chrislovsund@177
  4204
                    definesMap.put(alias.toUpperCase(Locale.ENGLISH), value);
chrislovsund@177
  4205
                }
chrislovsund@177
  4206
            }
chrislovsund@177
  4207
        }
chrislovsund@177
  4208
    }
chrislovsund@177
  4209
chrislovsund@177
  4210
    /**
chrislovsund@177
  4211
     * Replace exStr in the given text with newStr
chrislovsund@362
  4212
     *
chrislovsund@177
  4213
     * @param plsqlString
chrislovsund@177
  4214
     * @param exStr
chrislovsund@177
  4215
     * @param newStr
chrislovsund@177
  4216
     * @return
chrislovsund@177
  4217
     */
chrislovsund@177
  4218
    public String replaceText(
chrislovsund@177
  4219
            String plsqlString, String exStr, String newStr) {
chrislovsund@177
  4220
        if (plsqlString.indexOf(exStr) >= 0) {
chrislovsund@177
  4221
            plsqlString = plsqlString.replace(exStr, newStr);
chrislovsund@177
  4222
        }
chrislovsund@177
  4223
chrislovsund@177
  4224
        return plsqlString;
chrislovsund@177
  4225
    }
chrislovsund@177
  4226
chrislovsund@177
  4227
    /**
chrislovsund@177
  4228
     * Check whether the given offsets are in the same line
chrislovsund@362
  4229
     *
chrislovsund@177
  4230
     * @param doc
chrislovsund@177
  4231
     * @param offset1
chrislovsund@177
  4232
     * @param offset2
chrislovsund@177
  4233
     * @return
chrislovsund@177
  4234
     */
chrislovsund@177
  4235
    private boolean checkSameLine(Document doc, int offset1, int offset2) {
chrislovsund@177
  4236
        int startLine = offset2;
chrislovsund@177
  4237
        int endLine = offset2;
chrislovsund@177
  4238
chrislovsund@177
  4239
        TokenHierarchy tokenHier = TokenHierarchy.get(doc);
chrislovsund@177
  4240
        @SuppressWarnings("unchecked")
chrislovsund@177
  4241
        TokenSequence<PlsqlTokenId> ts = tokenHier.tokenSequence(PlsqlTokenId.language());
chrislovsund@177
  4242
        if (ts == null) {
chrislovsund@177
  4243
            return false;
chrislovsund@177
  4244
        }
chrislovsund@177
  4245
chrislovsund@177
  4246
        //go to the previous line break
chrislovsund@177
  4247
        ts.move(offset2);
chrislovsund@177
  4248
        boolean movePrevious = ts.movePrevious();
chrislovsund@177
  4249
        Token<PlsqlTokenId> tokenPre = ts.token();
chrislovsund@177
  4250
chrislovsund@177
  4251
        while (movePrevious) {
chrislovsund@177
  4252
            if (tokenPre.text().toString().contains("\n")) {
chrislovsund@177
  4253
                startLine = tokenPre.offset(tokenHier);
chrislovsund@177
  4254
                break;
chrislovsund@177
  4255
chrislovsund@177
  4256
            }
chrislovsund@177
  4257
            movePrevious = ts.movePrevious();
chrislovsund@177
  4258
            tokenPre = ts.token();
chrislovsund@177
  4259
        }
chrislovsund@177
  4260
chrislovsund@177
  4261
        //If cannot move previous and start line not set it is the document begin
chrislovsund@177
  4262
        if ((startLine == offset2) && (!movePrevious)) {
chrislovsund@177
  4263
            startLine = doc.getStartPosition().getOffset();
chrislovsund@177
  4264
        }
chrislovsund@177
  4265
chrislovsund@177
  4266
        //go to the next line break
chrislovsund@177
  4267
        ts.move(offset2);
chrislovsund@177
  4268
        boolean moveNext = ts.moveNext();
chrislovsund@177
  4269
        Token<PlsqlTokenId> tokenNext = ts.token();
chrislovsund@177
  4270
chrislovsund@177
  4271
        while (moveNext) {
chrislovsund@177
  4272
            if (tokenNext.text().toString().contains("\n")) {
chrislovsund@177
  4273
                endLine = tokenNext.offset(tokenHier);
chrislovsund@177
  4274
                break;
chrislovsund@177
  4275
            }
chrislovsund@177
  4276
jrechtacek@0
  4277
            moveNext = ts.moveNext();
chrislovsund@177
  4278
            tokenNext = ts.token();
chrislovsund@177
  4279
        }
chrislovsund@177
  4280
chrislovsund@177
  4281
        //If cannot move next and end line not set it is the document end
chrislovsund@177
  4282
        if ((endLine == offset2) && (!moveNext)) {
chrislovsund@177
  4283
            endLine = doc.getEndPosition().getOffset();
chrislovsund@177
  4284
        }
chrislovsund@177
  4285
chrislovsund@177
  4286
        if ((offset1 >= startLine) && (offset1 <= endLine)) {
chrislovsund@177
  4287
            if ((offset2 >= startLine) && (offset2 <= endLine)) {
chrislovsund@177
  4288
                return true;
jrechtacek@0
  4289
            }
chrislovsund@177
  4290
        }
chrislovsund@177
  4291
chrislovsund@177
  4292
        return false;
chrislovsund@177
  4293
    }
chrislovsund@177
  4294
chrislovsund@177
  4295
    /**
chrislovsund@177
  4296
     * Method that will check if blocks
chrislovsund@362
  4297
     *
chrislovsund@177
  4298
     * @param current
chrislovsund@177
  4299
     * @param ts
chrislovsund@177
  4300
     * @param parentBlocks
chrislovsund@177
  4301
     * @return
chrislovsund@177
  4302
     */
chrislovsund@177
  4303
    private List<PlsqlBlock> checkIfBlock(Token<PlsqlTokenId> current, TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
  4304
        Token<PlsqlTokenId> ifBegin = null;
chrislovsund@177
  4305
        Token<PlsqlTokenId> token = null;
chrislovsund@177
  4306
        int preOffset = -1;
chrislovsund@177
  4307
        List<PlsqlBlock> ifBlocks = new ArrayList<PlsqlBlock>();
chrislovsund@177
  4308
        List<PlsqlBlock> lstChild = new ArrayList<PlsqlBlock>();
chrislovsund@177
  4309
        boolean moveNext = false;
chrislovsund@177
  4310
chrislovsund@177
  4311
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
  4312
        if (sqlPlusLine(ts)) {
chrislovsund@177
  4313
            return null;
chrislovsund@177
  4314
        }
chrislovsund@177
  4315
chrislovsund@177
  4316
        moveNext = ts.moveNext();
chrislovsund@177
  4317
        token = ts.token();
chrislovsund@177
  4318
        ifBegin = current;
chrislovsund@177
  4319
        String name = ifBegin.text().toString() + " ";
chrislovsund@177
  4320
        boolean isThen = false;
chrislovsund@177
  4321
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@177
  4322
        //If this is an else check we need to ignore then
chrislovsund@177
  4323
        if (name.trim().equalsIgnoreCase("ELSE")) {
chrislovsund@177
  4324
            isThen = true;
chrislovsund@177
  4325
        }
chrislovsund@177
  4326
        while (moveNext) {
chrislovsund@177
  4327
            String image = token.text().toString();
chrislovsund@177
  4328
            PlsqlTokenId tokenID = token.id();
chrislovsund@177
  4329
chrislovsund@177
  4330
            if ((token != null) && (!image.equals(";")) && (token.offset(tokenHierarchy) > endParse)) {
chrislovsund@177
  4331
                break;
jrechtacek@0
  4332
            }
jrechtacek@0
  4333
chrislovsund@177
  4334
            if (image.equalsIgnoreCase("ELSE")) {
chrislovsund@177
  4335
                if (isThen) {
chrislovsund@177
  4336
                    PlsqlBlock block = new PlsqlBlock(ifBegin.offset(tokenHierarchy), preOffset, name.trim(), "", PlsqlBlockType.IF);
chrislovsund@177
  4337
                    if (block != null) {
jrechtacek@0
  4338
                        //add children
jrechtacek@0
  4339
                        addChildren(block, lstChild, parentBlocks);
jrechtacek@0
  4340
                        ifBlocks.add(block);
jrechtacek@0
  4341
                        lstChild.clear();
chrislovsund@177
  4342
                    }
chrislovsund@177
  4343
chrislovsund@177
  4344
                    name = "ELSE";
chrislovsund@177
  4345
                    ifBegin = token;
chrislovsund@177
  4346
                } else {
chrislovsund@177
  4347
                    break;
chrislovsund@177
  4348
                }
chrislovsund@177
  4349
            } else if (image.equalsIgnoreCase("ELSIF")) {
chrislovsund@177
  4350
                if (isThen) {
chrislovsund@177
  4351
                    PlsqlBlock block = new PlsqlBlock(ifBegin.offset(tokenHierarchy), preOffset, name.trim(), "", PlsqlBlockType.IF);
chrislovsund@177
  4352
                    if (block != null) {
chrislovsund@177
  4353
                        //add children
chrislovsund@177
  4354
                        addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  4355
                        ifBlocks.add(block);
chrislovsund@177
  4356
                        lstChild.clear();
chrislovsund@177
  4357
                    }
chrislovsund@177
  4358
                    //reset everything for ELSE IF
chrislovsund@177
  4359
                    name = "ELSIF";
chrislovsund@177
  4360
                    isThen = false;
chrislovsund@177
  4361
                    ifBegin = token;
chrislovsund@177
  4362
                } else {
chrislovsund@177
  4363
                    break;
chrislovsund@177
  4364
                }
chrislovsund@177
  4365
            } else if (image.equalsIgnoreCase("END")) {
chrislovsund@177
  4366
                if (isThen) {
chrislovsund@177
  4367
                    boolean next = getNextNonWhitespace(ts, true);
chrislovsund@177
  4368
                    Token<PlsqlTokenId> nextTok = ts.token();
chrislovsund@177
  4369
                    if (next && nextTok.text().toString().equalsIgnoreCase("IF")) {
chrislovsund@177
  4370
                        next = getNextNonWhitespace(ts, true);
chrislovsund@177
  4371
                        nextTok = ts.token();
chrislovsund@177
  4372
                        if (next && nextTok.text().toString().equalsIgnoreCase(";")) {
chrislovsund@177
  4373
                            ts.moveNext();
chrislovsund@177
  4374
                            PlsqlBlock block = new PlsqlBlock(ifBegin.offset(tokenHierarchy), ts.offset(), name.trim(), "", PlsqlBlockType.IF);
chrislovsund@177
  4375
                            if (block != null) {
chrislovsund@177
  4376
                                //add children
chrislovsund@177
  4377
                                addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  4378
                                ifBlocks.add(block);
chrislovsund@177
  4379
                                lstChild.clear();
chrislovsund@177
  4380
                                break;
chrislovsund@177
  4381
                            }
chrislovsund@177
  4382
                        } else {
chrislovsund@177
  4383
                            break;
chrislovsund@177
  4384
                        }
chrislovsund@177
  4385
                    }
chrislovsund@177
  4386
                } else {
chrislovsund@177
  4387
                    break;
chrislovsund@177
  4388
                }
chrislovsund@177
  4389
            } else if (image.equalsIgnoreCase("THEN")) {
chrislovsund@177
  4390
                isThen = true;
chrislovsund@177
  4391
            } else if (image.equalsIgnoreCase("IF")) {
chrislovsund@177
  4392
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  4393
                List children = checkIfBlock(token, ts, lstChild);
chrislovsund@177
  4394
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4395
chrislovsund@177
  4396
                    ts.move(beforeOff);
chrislovsund@177
  4397
                    moveNext = ts.moveNext();
chrislovsund@177
  4398
                } else {
chrislovsund@177
  4399
                    for (int i = 0; i < children.size(); i++) {
chrislovsund@177
  4400
                        PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@177
  4401
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4402
                            lstChild.add(child);
chrislovsund@177
  4403
                        }
chrislovsund@177
  4404
                    }
chrislovsund@177
  4405
                }
chrislovsund@177
  4406
            } else if (image.equalsIgnoreCase("CASE")) {
chrislovsund@177
  4407
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  4408
                List children = checkCaseBlock(token, ts, lstChild, false);
chrislovsund@177
  4409
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4410
chrislovsund@177
  4411
                    ts.move(beforeOff);
chrislovsund@177
  4412
                    moveNext = ts.moveNext();
chrislovsund@177
  4413
                } else {
chrislovsund@177
  4414
                    for (int i = 0; i < children.size(); i++) {
chrislovsund@177
  4415
                        PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@177
  4416
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4417
                            lstChild.add(child);
chrislovsund@177
  4418
                        }
chrislovsund@177
  4419
                    }
chrislovsund@177
  4420
                }
chrislovsund@177
  4421
            } else if (tokenID == PlsqlTokenId.KEYWORD && image.equalsIgnoreCase("DECLARE")) {
chrislovsund@177
  4422
                PlsqlBlock child = checkDeclareBlock(token, ts, lstChild);
chrislovsund@177
  4423
                if (child != null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4424
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4425
                        lstChild.add(child);
chrislovsund@177
  4426
                    }
chrislovsund@177
  4427
                }
chrislovsund@177
  4428
            } else if (tokenID == PlsqlTokenId.KEYWORD && (image.equalsIgnoreCase("BEGIN"))) {
chrislovsund@177
  4429
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  4430
                PlsqlBlock child = checkBeginBlock(token, ts, lstChild);
chrislovsund@177
  4431
                if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4432
chrislovsund@177
  4433
                    ts.move(beforeOff);
chrislovsund@177
  4434
                    moveNext = ts.moveNext();
chrislovsund@177
  4435
                } else {
chrislovsund@177
  4436
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4437
                        lstChild.add(child);
chrislovsund@177
  4438
                    }
chrislovsund@177
  4439
                }
chrislovsund@177
  4440
            } else if (image.equalsIgnoreCase("WHILE")
chrislovsund@177
  4441
                    || image.equalsIgnoreCase("FOR")
chrislovsund@177
  4442
                    || image.equalsIgnoreCase("LOOP")) {
chrislovsund@177
  4443
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  4444
                if (!unsuccessBlocks.contains(beforeOff)) {
chrislovsund@177
  4445
                    PlsqlBlock child = checkLoopBlock(token, ts, lstChild);
chrislovsund@177
  4446
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4447
                        unsuccessBlocks.add(beforeOff);
chrislovsund@177
  4448
                        ts.move(beforeOff);
chrislovsund@177
  4449
                        moveNext = ts.moveNext();
chrislovsund@177
  4450
                    } else {
chrislovsund@177
  4451
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4452
                            lstChild.add(child);
chrislovsund@177
  4453
                        }
chrislovsund@177
  4454
                    }
chrislovsund@177
  4455
                }
chrislovsund@177
  4456
            } else if (image.equalsIgnoreCase("TABLE")
chrislovsund@177
  4457
                    || image.equalsIgnoreCase("INDEX")
chrislovsund@177
  4458
                    || image.equalsIgnoreCase("SELECT")
chrislovsund@177
  4459
                    || image.equalsIgnoreCase("UPDATE")
chrislovsund@177
  4460
                    || image.equalsIgnoreCase("DELETE")
chrislovsund@177
  4461
                    || image.equalsIgnoreCase("INSERT")
chrislovsund@177
  4462
                    || image.equalsIgnoreCase("MERGE")
chrislovsund@177
  4463
                    || image.equalsIgnoreCase("DROP")
chrislovsund@177
  4464
                    || image.equalsIgnoreCase("SEQUENCE")) {
chrislovsund@177
  4465
                if (!isNotBlockStart(token, ts)) {
chrislovsund@177
  4466
                    int offset = token.offset(tokenHierarchy);
chrislovsund@177
  4467
                    PlsqlBlock child = checkStatementBlock(token, ts, parentBlocks);
chrislovsund@177
  4468
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4469
chrislovsund@177
  4470
                        ts.move(offset);
chrislovsund@177
  4471
                        ts.moveNext();
chrislovsund@177
  4472
                    } else {
chrislovsund@177
  4473
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4474
                            lstChild.add(child);
chrislovsund@177
  4475
                        }
chrislovsund@177
  4476
                    }
chrislovsund@177
  4477
                }
chrislovsund@177
  4478
            } else if (image.equalsIgnoreCase("PROCEDURE")
chrislovsund@177
  4479
                    || image.equalsIgnoreCase("FUNCTION")
chrislovsund@177
  4480
                    || image.equalsIgnoreCase("CREATE")) {
chrislovsund@177
  4481
                break;
chrislovsund@177
  4482
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
  4483
                //only single comment line
chrislovsund@177
  4484
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
  4485
                    customStartToken = token;
chrislovsund@177
  4486
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
  4487
                    if (customStartToken != null) {
chrislovsund@177
  4488
                        String fname = customStartToken.text().toString();
chrislovsund@177
  4489
                        int index = fname.toUpperCase(Locale.ENGLISH).indexOf("<FOLD>");
chrislovsund@177
  4490
                        fname = fname.substring(index + 7).trim();
chrislovsund@177
  4491
                        if (ts.moveNext()) {
chrislovsund@177
  4492
                            token = ts.token();
chrislovsund@177
  4493
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@177
  4494
                                    token.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
  4495
                            customFoldBlocks.add(custom);
chrislovsund@177
  4496
                        }
chrislovsund@177
  4497
                        customStartToken = null;
chrislovsund@177
  4498
                    }
chrislovsund@177
  4499
                } else {
chrislovsund@177
  4500
                    PlsqlBlock child = checkComment(token, ts);
chrislovsund@177
  4501
                    if (child != null) {
chrislovsund@177
  4502
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4503
                            lstChild.add(child);
chrislovsund@177
  4504
                        }
chrislovsund@177
  4505
                    }
chrislovsund@177
  4506
                }
chrislovsund@177
  4507
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@177
  4508
                int start = token.offset(tokenHierarchy);
chrislovsund@177
  4509
                PlsqlBlock child = new PlsqlBlock(start,
chrislovsund@177
  4510
                        start + token.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@177
  4511
                if (child != null) {
chrislovsund@177
  4512
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4513
                        lstChild.add(child);
chrislovsund@177
  4514
                    }
chrislovsund@177
  4515
                }
chrislovsund@177
  4516
            } else if (!isThen) {
chrislovsund@177
  4517
                name = name + image;
chrislovsund@177
  4518
            }
chrislovsund@177
  4519
chrislovsund@177
  4520
            preOffset = ts.offset();
chrislovsund@177
  4521
            moveNext = ts.moveNext();
chrislovsund@177
  4522
            token = ts.token();
chrislovsund@177
  4523
        }
chrislovsund@177
  4524
chrislovsund@177
  4525
        return ifBlocks;
chrislovsund@177
  4526
    }
chrislovsund@177
  4527
chrislovsund@177
  4528
    /**
chrislovsund@177
  4529
     * Method that will check case blocks
chrislovsund@362
  4530
     *
chrislovsund@177
  4531
     * @param current
chrislovsund@177
  4532
     * @param ts
chrislovsund@177
  4533
     * @param parentBlocks
chrislovsund@177
  4534
     * @return
chrislovsund@177
  4535
     */
chrislovsund@177
  4536
    private List<PlsqlBlock> checkCaseBlock(Token<PlsqlTokenId> current, TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> parentBlocks, boolean isStatement) {
chrislovsund@177
  4537
        Token<PlsqlTokenId> caseBegin = null;
chrislovsund@177
  4538
        Token<PlsqlTokenId> token = null;
chrislovsund@177
  4539
        int preOffset = -1;
chrislovsund@177
  4540
        List<PlsqlBlock> caseBlocks = new ArrayList<PlsqlBlock>();
chrislovsund@177
  4541
        List<PlsqlBlock> lstChild = new ArrayList<PlsqlBlock>();
chrislovsund@177
  4542
        boolean moveNext = false;
chrislovsund@177
  4543
chrislovsund@177
  4544
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
  4545
        if (!isStatement && sqlPlusLine(ts)) {
chrislovsund@177
  4546
            return null;
chrislovsund@177
  4547
        }
chrislovsund@177
  4548
chrislovsund@177
  4549
        moveNext = ts.moveNext();
chrislovsund@177
  4550
        token = ts.token();
chrislovsund@177
  4551
        caseBegin = current;
chrislovsund@177
  4552
        String name = caseBegin.text().toString() + " ";
chrislovsund@177
  4553
        boolean isThen = false;
chrislovsund@177
  4554
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@177
  4555
        //If this is an else check we need to ignore then
chrislovsund@177
  4556
        if (name.trim().equalsIgnoreCase("ELSE")) {
chrislovsund@177
  4557
            isThen = true;
chrislovsund@177
  4558
        }
chrislovsund@177
  4559
chrislovsund@177
  4560
        while (moveNext) {
chrislovsund@177
  4561
            String image = token.text().toString();
chrislovsund@177
  4562
            PlsqlTokenId tokenID = token.id();
chrislovsund@177
  4563
chrislovsund@177
  4564
            if ((token != null) && (!image.equals(";")) && (token.offset(tokenHierarchy) > endParse)) {
chrislovsund@177
  4565
                break;
chrislovsund@177
  4566
            }
chrislovsund@177
  4567
chrislovsund@177
  4568
            if (image.equalsIgnoreCase("ELSE")) {
chrislovsund@177
  4569
                if (isThen) {
chrislovsund@177
  4570
                    PlsqlBlock block = new PlsqlBlock(caseBegin.offset(tokenHierarchy), preOffset, name.trim(), "", PlsqlBlockType.CASE);
chrislovsund@177
  4571
                    if (block != null) {
chrislovsund@177
  4572
                        //add children
chrislovsund@177
  4573
                        addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  4574
                        caseBlocks.add(block);
chrislovsund@177
  4575
                        lstChild.clear();
chrislovsund@177
  4576
                    }
chrislovsund@177
  4577
chrislovsund@177
  4578
                    name = "ELSE";
chrislovsund@177
  4579
                    caseBegin = token;
chrislovsund@177
  4580
                } else {
chrislovsund@177
  4581
                    break;
chrislovsund@177
  4582
                }
chrislovsund@177
  4583
            } else if (image.equalsIgnoreCase("WHEN")) {
chrislovsund@177
  4584
                if (isThen) {
chrislovsund@177
  4585
                    PlsqlBlock block = new PlsqlBlock(caseBegin.offset(tokenHierarchy), preOffset, name.trim(), "", PlsqlBlockType.CASE);
chrislovsund@177
  4586
                    if (block != null) {
chrislovsund@177
  4587
                        //add children
chrislovsund@177
  4588
                        addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  4589
                        caseBlocks.add(block);
chrislovsund@177
  4590
                        lstChild.clear();
chrislovsund@177
  4591
                    }
chrislovsund@177
  4592
                    //reset everything for ELSE IF
chrislovsund@177
  4593
                    name = "WHEN";
chrislovsund@177
  4594
                    isThen = false;
chrislovsund@177
  4595
                    caseBegin = token;
chrislovsund@177
  4596
                } else if (name.trim().startsWith("CASE")) { //first WHEN
chrislovsund@177
  4597
                    name = name + image;
chrislovsund@177
  4598
                } else {
chrislovsund@177
  4599
                    break;
chrislovsund@177
  4600
                }
chrislovsund@177
  4601
            } else if (image.equalsIgnoreCase("END")) {
chrislovsund@177
  4602
                if (isThen) {
chrislovsund@177
  4603
                    boolean next = false;
chrislovsund@177
  4604
                    Token<PlsqlTokenId> nextTok = token;
chrislovsund@177
  4605
                    int offset = ts.offset();
chrislovsund@177
  4606
chrislovsund@177
  4607
                    next = getNextNonWhitespace(ts, true);
chrislovsund@177
  4608
                    nextTok = ts.token();
chrislovsund@177
  4609
                    if (next && nextTok.text().toString().equalsIgnoreCase("CASE")) {
chrislovsund@177
  4610
                        next = getNextNonWhitespace(ts, true);
chrislovsund@177
  4611
                        nextTok = ts.token();
chrislovsund@177
  4612
                    }
chrislovsund@177
  4613
                    if (!(!isStatement && next && nextTok.text().toString().equalsIgnoreCase(";"))) {
chrislovsund@177
  4614
                        ts.move(offset);
chrislovsund@177
  4615
                        ts.moveNext();
chrislovsund@177
  4616
                    }
chrislovsund@177
  4617
chrislovsund@177
  4618
                    ts.moveNext();
chrislovsund@177
  4619
                    PlsqlBlock block = new PlsqlBlock(caseBegin.offset(tokenHierarchy), ts.offset(), name.trim(), "", PlsqlBlockType.CASE);
chrislovsund@177
  4620
                    if (block != null) {
chrislovsund@177
  4621
                        //add children
chrislovsund@177
  4622
                        addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  4623
                        caseBlocks.add(block);
chrislovsund@177
  4624
                        lstChild.clear();
chrislovsund@177
  4625
                        if (isStatement && ts.token().toString().equals(";")) {
chrislovsund@177
  4626
                            ts.movePrevious();
chrislovsund@177
  4627
                        }
jrechtacek@0
  4628
                        break;
chrislovsund@177
  4629
                    }
chrislovsund@177
  4630
                } else {
chrislovsund@177
  4631
                    break;
chrislovsund@177
  4632
                }
chrislovsund@177
  4633
            } else if (image.equalsIgnoreCase("THEN")) {
chrislovsund@177
  4634
                isThen = true;
chrislovsund@177
  4635
            } else if (image.equalsIgnoreCase("IF")) {
chrislovsund@177
  4636
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  4637
                List children = checkIfBlock(token, ts, lstChild);
chrislovsund@177
  4638
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4639
chrislovsund@177
  4640
                    ts.move(beforeOff);
chrislovsund@177
  4641
                    moveNext = ts.moveNext();
chrislovsund@177
  4642
                } else {
chrislovsund@177
  4643
                    for (int i = 0; i < children.size(); i++) {
chrislovsund@177
  4644
                        PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@177
  4645
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4646
                            lstChild.add(child);
chrislovsund@177
  4647
                        }
chrislovsund@177
  4648
                    }
chrislovsund@177
  4649
                }
chrislovsund@177
  4650
            } else if (image.equalsIgnoreCase("CASE")) {
chrislovsund@177
  4651
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  4652
                List children = checkCaseBlock(token, ts, lstChild, isStatement);
chrislovsund@177
  4653
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4654
chrislovsund@177
  4655
                    ts.move(beforeOff);
chrislovsund@177
  4656
                    moveNext = ts.moveNext();
chrislovsund@177
  4657
                } else {
chrislovsund@177
  4658
                    for (int i = 0; i < children.size(); i++) {
chrislovsund@177
  4659
                        PlsqlBlock child = (PlsqlBlock) children.get(i);
chrislovsund@177
  4660
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4661
                            lstChild.add(child);
chrislovsund@177
  4662
                        }
chrislovsund@177
  4663
                    }
chrislovsund@177
  4664
                }
chrislovsund@177
  4665
            } else if (image.equalsIgnoreCase("WHILE")
chrislovsund@177
  4666
                    || image.equalsIgnoreCase("FOR")
chrislovsund@177
  4667
                    || image.equalsIgnoreCase("LOOP")) {
chrislovsund@177
  4668
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  4669
                if (!unsuccessBlocks.contains(beforeOff)) {
chrislovsund@177
  4670
                    PlsqlBlock child = checkLoopBlock(token, ts, lstChild);
chrislovsund@177
  4671
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4672
                        unsuccessBlocks.add(beforeOff);
chrislovsund@177
  4673
                        ts.move(beforeOff);
chrislovsund@177
  4674
                        moveNext = ts.moveNext();
chrislovsund@177
  4675
                    } else {
chrislovsund@177
  4676
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4677
                            lstChild.add(child);
chrislovsund@177
  4678
                        }
chrislovsund@177
  4679
                    }
chrislovsund@177
  4680
                }
chrislovsund@177
  4681
            } else if (tokenID == PlsqlTokenId.KEYWORD && (image.equalsIgnoreCase("BEGIN"))) {
chrislovsund@177
  4682
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  4683
                PlsqlBlock child = checkBeginBlock(token, ts, lstChild);
chrislovsund@177
  4684
                if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4685
chrislovsund@177
  4686
                    ts.move(beforeOff);
chrislovsund@177
  4687
                    moveNext = ts.moveNext();
chrislovsund@177
  4688
                } else {
chrislovsund@177
  4689
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4690
                        lstChild.add(child);
chrislovsund@177
  4691
                    }
chrislovsund@177
  4692
                }
chrislovsund@177
  4693
            } else if (image.equalsIgnoreCase("TABLE")
chrislovsund@177
  4694
                    || image.equalsIgnoreCase("INDEX")
chrislovsund@177
  4695
                    || image.equalsIgnoreCase("SELECT")
chrislovsund@177
  4696
                    || image.equalsIgnoreCase("UPDATE")
chrislovsund@177
  4697
                    || image.equalsIgnoreCase("DELETE")
chrislovsund@177
  4698
                    || image.equalsIgnoreCase("INSERT")
chrislovsund@177
  4699
                    || image.equalsIgnoreCase("MERGE")
chrislovsund@177
  4700
                    || image.equalsIgnoreCase("DROP")
chrislovsund@177
  4701
                    || image.equalsIgnoreCase("SEQUENCE")) {
chrislovsund@177
  4702
                if (!isNotBlockStart(token, ts)) {
chrislovsund@177
  4703
                    int offset = token.offset(tokenHierarchy);
chrislovsund@177
  4704
                    PlsqlBlock child = checkStatementBlock(token, ts, parentBlocks);
chrislovsund@177
  4705
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4706
chrislovsund@177
  4707
                        ts.move(offset);
chrislovsund@177
  4708
                        ts.moveNext();
chrislovsund@177
  4709
                    } else {
chrislovsund@177
  4710
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4711
                            lstChild.add(child);
chrislovsund@177
  4712
                        }
chrislovsund@177
  4713
                    }
chrislovsund@177
  4714
                }
chrislovsund@177
  4715
            } else if (image.equalsIgnoreCase("PROCEDURE")
chrislovsund@177
  4716
                    || image.equalsIgnoreCase("FUNCTION")
chrislovsund@177
  4717
                    || image.equalsIgnoreCase("CREATE")) {
chrislovsund@177
  4718
                break;
chrislovsund@177
  4719
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
  4720
                //only single comment line
chrislovsund@177
  4721
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
  4722
                    customStartToken = token;
chrislovsund@177
  4723
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
  4724
                    if (customStartToken != null) {
chrislovsund@177
  4725
                        if (ts.moveNext()) {
chrislovsund@177
  4726
                            token = ts.token();
chrislovsund@177
  4727
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@177
  4728
                                    token.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
  4729
                            customFoldBlocks.add(custom);
chrislovsund@177
  4730
                        }
chrislovsund@177
  4731
                        customStartToken = null;
chrislovsund@177
  4732
                    }
chrislovsund@177
  4733
                } else {
chrislovsund@177
  4734
                    PlsqlBlock child = checkComment(token, ts);
chrislovsund@177
  4735
                    if (child != null) {
chrislovsund@177
  4736
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4737
                            lstChild.add(child);
chrislovsund@177
  4738
                        }
chrislovsund@177
  4739
                    }
chrislovsund@177
  4740
                }
chrislovsund@177
  4741
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@177
  4742
                int start = token.offset(tokenHierarchy);
chrislovsund@177
  4743
                PlsqlBlock child = new PlsqlBlock(start,
chrislovsund@177
  4744
                        start + token.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@362
  4745
                if (checkExisting(child, lstChild) == false) {
chrislovsund@362
  4746
                    lstChild.add(child);
chrislovsund@177
  4747
                }
chrislovsund@177
  4748
            } else if (!isThen) {
chrislovsund@177
  4749
                name = name + image;
jrechtacek@0
  4750
            }
chrislovsund@177
  4751
chrislovsund@177
  4752
            preOffset = ts.offset();
chrislovsund@177
  4753
            moveNext = ts.moveNext();
chrislovsund@177
  4754
            token = ts.token();
chrislovsund@177
  4755
        }
chrislovsund@177
  4756
chrislovsund@177
  4757
        return caseBlocks;
chrislovsund@177
  4758
    }
chrislovsund@177
  4759
chrislovsund@177
  4760
    /**
chrislovsund@177
  4761
     * Method that will return the prefix of the given block
chrislovsund@362
  4762
     *
chrislovsund@177
  4763
     * @param startOffset
chrislovsund@177
  4764
     * @param ts
chrislovsund@177
  4765
     * @return
chrislovsund@177
  4766
     */
chrislovsund@177
  4767
    private String getPreceedingText(int startOffset, TokenSequence<PlsqlTokenId> ts) {
chrislovsund@177
  4768
        String prefix = "";
chrislovsund@177
  4769
        int offset = ts.offset();
chrislovsund@177
  4770
        ts.move(startOffset);
chrislovsund@177
  4771
        ts.moveNext();
chrislovsund@177
  4772
        Token<PlsqlTokenId> token = ts.token();
chrislovsund@177
  4773
chrislovsund@177
  4774
        while (ts.movePrevious()) {
chrislovsund@177
  4775
            token = ts.token();
chrislovsund@177
  4776
            String image = token.text().toString();
chrislovsund@177
  4777
chrislovsund@177
  4778
            if (image.contains("\n")) {
chrislovsund@177
  4779
                break;
jrechtacek@0
  4780
            }
chrislovsund@177
  4781
chrislovsund@177
  4782
            prefix = token.text().toString() + prefix;
chrislovsund@177
  4783
        }
chrislovsund@177
  4784
chrislovsund@177
  4785
        ts.move(offset);
chrislovsund@177
  4786
        ts.moveNext();
chrislovsund@177
  4787
        return prefix;
chrislovsund@177
  4788
    }
chrislovsund@177
  4789
chrislovsund@177
  4790
    /**
chrislovsund@177
  4791
     * Method that will check loop blocks
chrislovsund@362
  4792
     *
chrislovsund@177
  4793
     * @param current
chrislovsund@177
  4794
     * @param ts
chrislovsund@177
  4795
     * @param parentBlocks
chrislovsund@177
  4796
     * @return
chrislovsund@177
  4797
     */
chrislovsund@177
  4798
    private PlsqlBlock checkLoopBlock(Token<PlsqlTokenId> current, TokenSequence<PlsqlTokenId> ts, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
  4799
        Token<PlsqlTokenId> loopBegin = null;
chrislovsund@177
  4800
        Token<PlsqlTokenId> token = null;
chrislovsund@177
  4801
        List<PlsqlBlock> lstChild = new ArrayList<PlsqlBlock>();
chrislovsund@177
  4802
        PlsqlBlock block = null;
chrislovsund@177
  4803
        boolean moveNext = false;
chrislovsund@177
  4804
chrislovsund@177
  4805
        //Check whether the beginning is in a SQL Plus command
chrislovsund@177
  4806
        if (sqlPlusLine(ts)) {
chrislovsund@177
  4807
            return null;
chrislovsund@177
  4808
        }
chrislovsund@177
  4809
chrislovsund@177
  4810
        moveNext = ts.moveNext();
chrislovsund@177
  4811
        token = ts.token();
chrislovsund@177
  4812
        loopBegin = current;
chrislovsund@177
  4813
        boolean isLoop = false;
chrislovsund@177
  4814
        Token<PlsqlTokenId> customStartToken = null;
chrislovsund@177
  4815
        PlsqlBlockType type = PlsqlBlockType.LOOP;
chrislovsund@177
  4816
        String name = "";
chrislovsund@177
  4817
        if (loopBegin.text().toString().equalsIgnoreCase("LOOP")) {
chrislovsund@177
  4818
            isLoop = true;
chrislovsund@177
  4819
        } else if (loopBegin.text().toString().equalsIgnoreCase("WHILE")) {
chrislovsund@177
  4820
            type = PlsqlBlockType.WHILE_LOOP;
chrislovsund@177
  4821
        } else if (loopBegin.text().toString().equalsIgnoreCase("FOR")) {
chrislovsund@177
  4822
            type = PlsqlBlockType.FOR_LOOP;
chrislovsund@177
  4823
        }
chrislovsund@177
  4824
chrislovsund@177
  4825
        while (moveNext) {
chrislovsund@177
  4826
            String image = token.text().toString();
chrislovsund@177
  4827
            PlsqlTokenId tokenID = token.id();
chrislovsund@177
  4828
chrislovsund@177
  4829
            if ((token != null) && (!image.equals(";")) && (token.offset(tokenHierarchy) > endParse)) {
chrislovsund@177
  4830
                break;
jrechtacek@0
  4831
            }
chrislovsund@177
  4832
chrislovsund@177
  4833
            if (!isLoop && image.equalsIgnoreCase("LOOP")) {
chrislovsund@177
  4834
                isLoop = true;
chrislovsund@177
  4835
            } else if (image.equalsIgnoreCase("END")) {
chrislovsund@177
  4836
                if (isLoop) {
chrislovsund@177
  4837
                    boolean next = getNextNonWhitespace(ts, true);
chrislovsund@177
  4838
                    Token<PlsqlTokenId> nextTok = ts.token();
chrislovsund@177
  4839
                    if (next && nextTok.text().toString().equalsIgnoreCase("LOOP")) {
chrislovsund@177
  4840
                        next = getNextNonWhitespace(ts, true);
chrislovsund@177
  4841
                        nextTok = ts.token();
chrislovsund@177
  4842
                        if (next && nextTok.text().toString().equalsIgnoreCase(";")) {
chrislovsund@177
  4843
                            ts.moveNext();
chrislovsund@177
  4844
                            block = new PlsqlBlock(loopBegin.offset(tokenHierarchy), ts.offset(), name.trim(), "", type);
chrislovsund@177
  4845
                            break;
chrislovsund@177
  4846
                        } else {
chrislovsund@177
  4847
                            break;
chrislovsund@177
  4848
                        }
chrislovsund@177
  4849
                    }
chrislovsund@177
  4850
                } else {
chrislovsund@177
  4851
                    break;
chrislovsund@177
  4852
                }
chrislovsund@177
  4853
            } else if (image.equalsIgnoreCase("IF")) {
chrislovsund@177
  4854
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  4855
                List<PlsqlBlock> children = checkIfBlock(token, ts, lstChild);
chrislovsund@177
  4856
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4857
chrislovsund@177
  4858
                    ts.move(beforeOff);
chrislovsund@177
  4859
                    moveNext = ts.moveNext();
chrislovsund@177
  4860
                } else {
chrislovsund@177
  4861
                    for (int i = 0; i < children.size(); i++) {
chrislovsund@177
  4862
                        PlsqlBlock child = children.get(i);
chrislovsund@177
  4863
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4864
                            lstChild.add(child);
chrislovsund@177
  4865
                        }
chrislovsund@177
  4866
                    }
chrislovsund@177
  4867
                }
chrislovsund@177
  4868
            } else if (image.equalsIgnoreCase("CASE")) {
chrislovsund@177
  4869
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  4870
                List<PlsqlBlock> children = checkCaseBlock(token, ts, lstChild, false);
chrislovsund@177
  4871
                if (children == null || children.isEmpty()) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4872
chrislovsund@177
  4873
                    ts.move(beforeOff);
chrislovsund@177
  4874
                    moveNext = ts.moveNext();
chrislovsund@177
  4875
                } else {
chrislovsund@177
  4876
                    for (int i = 0; i < children.size(); i++) {
chrislovsund@177
  4877
                        PlsqlBlock child = children.get(i);
chrislovsund@177
  4878
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4879
                            lstChild.add(child);
chrislovsund@177
  4880
                        }
chrislovsund@177
  4881
                    }
chrislovsund@177
  4882
                }
chrislovsund@177
  4883
            } else if (image.equalsIgnoreCase("LOOP")
chrislovsund@177
  4884
                    || image.equalsIgnoreCase("WHILE")
chrislovsund@177
  4885
                    || image.equalsIgnoreCase("FOR")) {
chrislovsund@177
  4886
                int beforeOff = token.offset(tokenHierarchy);
chrislovsund@177
  4887
                if (!unsuccessBlocks.contains(beforeOff)) {
chrislovsund@177
  4888
                    PlsqlBlock child = checkLoopBlock(token, ts, lstChild);
chrislovsund@177
  4889
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4890
                        unsuccessBlocks.add(beforeOff);
chrislovsund@177
  4891
                        ts.move(beforeOff);
chrislovsund@177
  4892
                        moveNext = ts.moveNext();
chrislovsund@177
  4893
                    } else {
chrislovsund@177
  4894
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4895
                            lstChild.add(child);
chrislovsund@177
  4896
                        }
chrislovsund@177
  4897
                    }
chrislovsund@177
  4898
                }
chrislovsund@177
  4899
            } else if (image.equalsIgnoreCase("TABLE")
chrislovsund@177
  4900
                    || image.equalsIgnoreCase("INDEX")
chrislovsund@177
  4901
                    || image.equalsIgnoreCase("SELECT")
chrislovsund@177
  4902
                    || image.equalsIgnoreCase("UPDATE")
chrislovsund@177
  4903
                    || image.equalsIgnoreCase("DELETE")
chrislovsund@177
  4904
                    || image.equalsIgnoreCase("INSERT")
chrislovsund@177
  4905
                    || image.equalsIgnoreCase("MERGE")
chrislovsund@177
  4906
                    || image.equalsIgnoreCase("DROP")
chrislovsund@177
  4907
                    || image.equalsIgnoreCase("SEQUENCE")) {
chrislovsund@177
  4908
                if (!isNotBlockStart(token, ts)) {
chrislovsund@177
  4909
                    int offset = token.offset(tokenHierarchy);
chrislovsund@177
  4910
                    PlsqlBlock child = checkStatementBlock(token, ts, parentBlocks);
chrislovsund@177
  4911
                    if (child == null) {//If inner check seems to have failed need to continue this one
chrislovsund@177
  4912
chrislovsund@177
  4913
                        ts.move(offset);
chrislovsund@177
  4914
                        ts.moveNext();
chrislovsund@177
  4915
                    } else {
chrislovsund@177
  4916
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4917
                            lstChild.add(child);
chrislovsund@177
  4918
                        }
chrislovsund@177
  4919
                    }
chrislovsund@177
  4920
                }
chrislovsund@177
  4921
            } else if (image.equalsIgnoreCase("PROCEDURE")
chrislovsund@177
  4922
                    || image.equalsIgnoreCase("FUNCTION")
chrislovsund@177
  4923
                    || image.equalsIgnoreCase("CREATE")) {
chrislovsund@177
  4924
                break;
chrislovsund@177
  4925
            } else if (tokenID == PlsqlTokenId.LINE_COMMENT) {
chrislovsund@177
  4926
                //only single comment line
chrislovsund@177
  4927
                if (image.toUpperCase(Locale.ENGLISH).contains("<FOLD>")) {
chrislovsund@177
  4928
                    customStartToken = token;
chrislovsund@177
  4929
                } else if (image.toUpperCase(Locale.ENGLISH).contains("<END-FOLD>")) {
chrislovsund@177
  4930
                    if (customStartToken != null) {
chrislovsund@177
  4931
                        if (ts.moveNext()) {
chrislovsund@177
  4932
                            token = ts.token();
chrislovsund@177
  4933
                            PlsqlBlock custom = new PlsqlBlock(customStartToken.offset(tokenHierarchy),
chrislovsund@177
  4934
                                    token.offset(tokenHierarchy), name, "", PlsqlBlockType.CUSTOM_FOLD);
chrislovsund@177
  4935
                            customFoldBlocks.add(custom);
chrislovsund@177
  4936
                        }
chrislovsund@177
  4937
chrislovsund@177
  4938
                        customStartToken = null;
chrislovsund@177
  4939
                    }
chrislovsund@177
  4940
                } else {
chrislovsund@177
  4941
                    PlsqlBlock child = checkComment(token, ts);
chrislovsund@177
  4942
                    if (child != null) {
chrislovsund@177
  4943
                        if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4944
                            lstChild.add(child);
chrislovsund@177
  4945
                        }
chrislovsund@177
  4946
                    }
chrislovsund@177
  4947
                }
chrislovsund@177
  4948
            } else if (tokenID == PlsqlTokenId.BLOCK_COMMENT) {
chrislovsund@177
  4949
                int start = token.offset(tokenHierarchy);
chrislovsund@177
  4950
                PlsqlBlock child = new PlsqlBlock(start,
chrislovsund@177
  4951
                        start + token.length(), "BLOCK COMMENT", "", PlsqlBlockType.COMMENT);
chrislovsund@177
  4952
                if (child != null) {
chrislovsund@177
  4953
                    if (checkExisting(child, lstChild) == false) {
chrislovsund@177
  4954
                        lstChild.add(child);
chrislovsund@177
  4955
                    }
chrislovsund@177
  4956
                }
chrislovsund@177
  4957
            } else if (!isLoop) {
chrislovsund@177
  4958
                name = name + image;
jrechtacek@0
  4959
            }
chrislovsund@177
  4960
chrislovsund@177
  4961
            moveNext = ts.moveNext();
chrislovsund@177
  4962
            token = ts.token();
chrislovsund@177
  4963
        }
chrislovsund@177
  4964
chrislovsund@177
  4965
        if (block != null) {
chrislovsund@177
  4966
            //add children
chrislovsund@177
  4967
            addChildren(block, lstChild, parentBlocks);
chrislovsund@177
  4968
        }
chrislovsund@177
  4969
chrislovsund@177
  4970
        return block;
chrislovsund@177
  4971
    }
chrislovsund@177
  4972
chrislovsund@177
  4973
    /**
chrislovsund@362
  4974
     * Method that will add the given child blocks to the block and remove from parent blocks if existing there
chrislovsund@362
  4975
     *
chrislovsund@177
  4976
     * @param block
chrislovsund@177
  4977
     * @param lstChild
chrislovsund@177
  4978
     * @param parentBlocks
chrislovsund@177
  4979
     */
chrislovsund@177
  4980
    private void addChildren(PlsqlBlock block, List<PlsqlBlock> lstChild, List<PlsqlBlock> parentBlocks) {
chrislovsund@177
  4981
        int size = lstChild.size();
chrislovsund@177
  4982
        for (int i = 0; i < size; i++) {
chrislovsund@177
  4983
            PlsqlBlock child = lstChild.get(i);
chrislovsund@177
  4984
            block.addChild(child);
chrislovsund@177
  4985
            removeFromParent(child, parentBlocks);
chrislovsund@177
  4986
        }
chrislovsund@177
  4987
    }
chrislovsund@177
  4988
chrislovsund@177
  4989
    public int getStartParse() {
chrislovsund@177
  4990
        return startParse;
chrislovsund@177
  4991
    }
chrislovsund@177
  4992
chrislovsund@177
  4993
    public int getEndParse() {
chrislovsund@177
  4994
        return endParse;
chrislovsund@177
  4995
    }
chrislovsund@177
  4996
chrislovsund@177
  4997
    public int getChangedLength() {
chrislovsund@177
  4998
        return changedLength;
chrislovsund@177
  4999
    }
jrechtacek@0
  5000
}