mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-09-10 03:53:21 +02:00
Bug 478938 - Automatically add source files to Qt Project File
Added basic content assist for built-in qmake variables since there are so many of them. Added a bunch of new classes dealing with basic parsing and modification of Qt Project Files. For now the parser is a simple regular expression matcher that finds instances of variables. The modification class supports preservation of indentation and comments that are tied to variables in the project file. Change-Id: I0539458d5c1cf29e6c9c1246e4e717e7cbec1b84 Signed-off-by: Matthew Bastien <mbastien@blackberry.com>
This commit is contained in:
parent
43da8ab7ac
commit
6c3f10576b
14 changed files with 1759 additions and 3 deletions
|
@ -0,0 +1,340 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* QNX Software Systems - Initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.qt.pro.parser.tests;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.qt.ui.pro.parser.QtProjectFileModifier;
|
||||||
|
import org.eclipse.jface.text.Document;
|
||||||
|
import org.eclipse.jface.text.IDocument;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
public class QtProjectFileModifierTest extends TestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_ReplaceValue_SingleValue() {
|
||||||
|
IDocument document = new Document("SOURCES += main.cpp"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
|
||||||
|
assertTrue(modifier.replaceVariableValue("SOURCES", "main.cpp", "main2.cpp")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||||
|
assertEquals("SOURCES += main2.cpp", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_ReplaceValue_HasCommentOnMainLine() {
|
||||||
|
IDocument document = new Document("SOURCES += main.cpp # This is a comment"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
|
||||||
|
assertTrue(modifier.replaceVariableValue("SOURCES", "main.cpp", "main2.cpp")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||||
|
assertEquals("SOURCES += main2.cpp # This is a comment", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_ReplaceValue_HasCommentOnSubsequentLine() {
|
||||||
|
IDocument document = new Document(
|
||||||
|
"SOURCES += main.cpp \\ # This is a comment\n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp # This is a comment"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
|
||||||
|
assertTrue(modifier.replaceVariableValue("SOURCES", "main2.cpp", "main3.cpp")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main.cpp \\ # This is a comment\n" //$NON-NLS-1$
|
||||||
|
+ " main3.cpp # This is a comment", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_ReplaceValue_MatchWholeLineFalse() {
|
||||||
|
IDocument document = new Document("CONFIG = qt debug"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
|
||||||
|
assertTrue(modifier.replaceVariableValue("CONFIG", "debug", "console", false)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||||
|
assertEquals(
|
||||||
|
"CONFIG = qt console", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_ReplaceValue_DoesNotExist() {
|
||||||
|
IDocument document = new Document("CONFIG = qt debug"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
|
||||||
|
assertFalse(modifier.replaceVariableValue("CONFIG", "console", "debug", false)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||||
|
assertEquals(
|
||||||
|
"CONFIG = qt debug", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_ReplaceMultilineValue_MatchWholeLineFalse() {
|
||||||
|
IDocument document = new Document(
|
||||||
|
"CONFIG = qt \\\n" //$NON-NLS-1$
|
||||||
|
+ " debug"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
|
||||||
|
assertTrue(modifier.replaceVariableValue("CONFIG", "debug", "console", false)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||||
|
assertEquals(
|
||||||
|
"CONFIG = qt \\\n" //$NON-NLS-1$
|
||||||
|
+ " console", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_ReplaceMultilineValue() {
|
||||||
|
IDocument document = new Document(
|
||||||
|
"SOURCES += main.cpp \\\n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
|
||||||
|
assertTrue(modifier.replaceVariableValue("SOURCES", "main2.cpp", "main3.cpp")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main.cpp \\\n" //$NON-NLS-1$
|
||||||
|
+ " main3.cpp", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_ReplaceMultilineValue_HasComment() {
|
||||||
|
IDocument document = new Document(
|
||||||
|
"SOURCES += main.cpp \\\n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp # This is a comment"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
|
||||||
|
assertTrue(modifier.replaceVariableValue("SOURCES", "main2.cpp", "main3.cpp")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main.cpp \\\n" //$NON-NLS-1$
|
||||||
|
+ " main3.cpp # This is a comment", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AddValue() {
|
||||||
|
IDocument document = new Document("SOURCES += main.cpp"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.addVariableValue("SOURCES", "main2.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main.cpp \\\n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AddValue_NoIndentation() {
|
||||||
|
IDocument document = new Document(
|
||||||
|
"SOURCES += main.cpp \\\n" //$NON-NLS-1$
|
||||||
|
+ "noindent.cpp"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.addVariableValue("SOURCES", "main2.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main.cpp \\\n" //$NON-NLS-1$
|
||||||
|
+ "noindent.cpp \\\n" //$NON-NLS-1$
|
||||||
|
+ "main2.cpp", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AddValue_AlreadyExists() {
|
||||||
|
IDocument document = new Document("SOURCES += main.cpp"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.addVariableValue("SOURCES", "main.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals("SOURCES += main.cpp", document.get()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AddValue_HasCommentOnMainLine() {
|
||||||
|
IDocument document = new Document("SOURCES += main.cpp # This is a comment"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.addVariableValue("SOURCES", "main2.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main.cpp \\ # This is a comment\n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AddValue_HasCommentOnSubsequentLine() {
|
||||||
|
IDocument document = new Document(
|
||||||
|
"SOURCES += main.cpp \\ # This is a comment \n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp # this is a comment\n\n"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.addVariableValue("SOURCES", "main3.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main.cpp \\ # This is a comment \n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp \\ # this is a comment\n" //$NON-NLS-1$
|
||||||
|
+ " main3.cpp\n\n", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AddValue_CommentIndentation() {
|
||||||
|
IDocument document = new Document(
|
||||||
|
"SOURCES += main.cpp \\ # Test comment\n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp \\ # Test comment2\n" //$NON-NLS-1$
|
||||||
|
+ " main3.cpp # Test comment3"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.addVariableValue("SOURCES", "main4.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main.cpp \\ # Test comment\n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp \\ # Test comment2\n" //$NON-NLS-1$
|
||||||
|
+ " main3.cpp \\ # Test comment3\n" //$NON-NLS-1$
|
||||||
|
+ " main4.cpp", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AddValue_MultipleVariables() {
|
||||||
|
IDocument document = new Document(
|
||||||
|
"SOURCES += main.cpp\n" //$NON-NLS-1$
|
||||||
|
+ "\n" //$NON-NLS-1$
|
||||||
|
+ "QT = app"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.addVariableValue("SOURCES", "main2.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main.cpp \\\n" + //$NON-NLS-1$
|
||||||
|
" main2.cpp\n" + //$NON-NLS-1$
|
||||||
|
"\n" + //$NON-NLS-1$
|
||||||
|
"QT = app", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AddValue_EmptyDocument() {
|
||||||
|
IDocument document = new Document("\t \n\n\t\n\n\n\n"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.addVariableValue("SOURCES", "main.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main.cpp\n", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AddValue_VariableDoesNotExist() {
|
||||||
|
IDocument document = new Document("CONFIG += qt debug"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.addVariableValue("SOURCES", "main.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"CONFIG += qt debug\n" //$NON-NLS-1$
|
||||||
|
+ "\n" //$NON-NLS-1$
|
||||||
|
+ "SOURCES += main.cpp\n", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AddValue_VariableDoesNotExist2() {
|
||||||
|
IDocument document = new Document("CONFIG += qt debug\n"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.addVariableValue("SOURCES", "main.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"CONFIG += qt debug\n" //$NON-NLS-1$
|
||||||
|
+ "\n" //$NON-NLS-1$
|
||||||
|
+ "SOURCES += main.cpp\n", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AddValue_VariableDoesNotExist3() {
|
||||||
|
IDocument document = new Document("CONFIG += qt debug\n\n"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.addVariableValue("SOURCES", "main.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"CONFIG += qt debug\n" //$NON-NLS-1$
|
||||||
|
+ "\n" //$NON-NLS-1$
|
||||||
|
+ "\n" //$NON-NLS-1$
|
||||||
|
+ "SOURCES += main.cpp\n", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_RemoveThenAddValue() {
|
||||||
|
IDocument document = new Document(
|
||||||
|
"SOURCES += main.cpp \\\n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp \\\n" //$NON-NLS-1$
|
||||||
|
+ " main3.cpp\n"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.removeVariableValue("SOURCES", "main3.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
modifier.addVariableValue("SOURCES", "main4.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main.cpp \\\n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp \\\n" //$NON-NLS-1$
|
||||||
|
+ " main4.cpp\n", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_RemoveValue_FirstLine() {
|
||||||
|
IDocument document = new Document(
|
||||||
|
"SOURCES += main.cpp \\ # Test comment\n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp \\ # Test comment2\n" //$NON-NLS-1$
|
||||||
|
+ " main3.cpp \\ # Test comment3\n" //$NON-NLS-1$
|
||||||
|
+ " main4.cpp # Test comment4"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.removeVariableValue("SOURCES", "main.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main2.cpp \\ # Test comment2\n" //$NON-NLS-1$
|
||||||
|
+ " main3.cpp \\ # Test comment3\n" //$NON-NLS-1$
|
||||||
|
+ " main4.cpp # Test comment4", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_RemoveValue_MiddleLine() {
|
||||||
|
IDocument document = new Document(
|
||||||
|
"SOURCES += main.cpp \\ # Test comment\n" //$NON-NLS-1$
|
||||||
|
+ " main2.cpp \\ # Test comment2\n" //$NON-NLS-1$
|
||||||
|
+ " main3.cpp \\ # Test comment3\n" //$NON-NLS-1$
|
||||||
|
+ " main4.cpp # Test comment4"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
QtProjectFileModifier modifier = new QtProjectFileModifier(document);
|
||||||
|
modifier.removeVariableValue("SOURCES", "main2.cpp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"SOURCES += main.cpp \\ # Test comment\n" //$NON-NLS-1$
|
||||||
|
+ " main3.cpp \\ # Test comment3\n" //$NON-NLS-1$
|
||||||
|
+ " main4.cpp # Test comment4", //$NON-NLS-1$
|
||||||
|
document.get());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,181 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* QNX Software Systems - Initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.qt.pro.parser.tests;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.qt.ui.pro.parser.QtProjectFileParser;
|
||||||
|
import org.eclipse.cdt.internal.qt.ui.pro.parser.QtProjectVariable;
|
||||||
|
import org.eclipse.jface.text.Document;
|
||||||
|
import org.eclipse.jface.text.IDocument;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
public class QtProjectFileParserTest extends TestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AssignmentOperator_Equals() {
|
||||||
|
IDocument document = new Document("SOURCES = main.cpp"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
|
||||||
|
List<QtProjectVariable> variables = parser.getAllVariables();
|
||||||
|
assertFalse("Unable to parse variable", variables.isEmpty()); //$NON-NLS-1$
|
||||||
|
assertEquals("Invalid assignment operator", "=", variables.get(0).getAssignmentOperator()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AssignmentOperator_PlusEquals() {
|
||||||
|
IDocument document = new Document("SOURCES += main.cpp"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
|
||||||
|
List<QtProjectVariable> variables = parser.getAllVariables();
|
||||||
|
assertFalse("Unable to parse variable", variables.isEmpty()); //$NON-NLS-1$
|
||||||
|
assertEquals("Invalid assignment operator", "+=", variables.get(0).getAssignmentOperator()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AssignmentOperator_MinusEquals() {
|
||||||
|
IDocument document = new Document("SOURCES -= main.cpp"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
|
||||||
|
List<QtProjectVariable> variables = parser.getAllVariables();
|
||||||
|
assertFalse("Unable to parse variable", variables.isEmpty()); //$NON-NLS-1$
|
||||||
|
assertEquals("Invalid assignment operator", "-=", variables.get(0).getAssignmentOperator()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_AssignmentOperator_AsterixEquals() {
|
||||||
|
IDocument document = new Document("SOURCES *= main.cpp"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
|
||||||
|
List<QtProjectVariable> variables = parser.getAllVariables();
|
||||||
|
assertFalse("Unable to parse variable", variables.isEmpty()); //$NON-NLS-1$
|
||||||
|
assertEquals("Invalid assignment operator", "*=", variables.get(0).getAssignmentOperator()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_CommentedVariable() {
|
||||||
|
IDocument document = new Document("# SOURCES += main.cpp"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
assertTrue("Found variable even though it was commented", parser.getAllVariables().isEmpty()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_CommentedVariable2() {
|
||||||
|
IDocument document = new Document("SOURCES # += main.cpp"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
assertTrue("Found variable even though it was commented", parser.getAllVariables().isEmpty()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_MalformedVariable() {
|
||||||
|
IDocument document = new Document("MY VARIABLE # += main.cpp"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
assertTrue("Found variable even though it was malformed", parser.getAllVariables().isEmpty()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_MalformedVariable2() {
|
||||||
|
IDocument document = new Document("\\SOURCES # += main.cpp"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
assertTrue("Found variable even though it was malformed", parser.getAllVariables().isEmpty()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_FullyQualifiedName() {
|
||||||
|
IDocument document = new Document("fully.qualified.Name += main.cpp"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
|
||||||
|
QtProjectVariable sources = parser.getVariable("fully.qualified.Name"); //$NON-NLS-1$
|
||||||
|
assertNotNull("Unable to parse variable", sources); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_SingleLineVariable() {
|
||||||
|
IDocument document = new Document("SOURCES += main.cpp"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
|
||||||
|
QtProjectVariable sources = parser.getVariable("SOURCES"); //$NON-NLS-1$
|
||||||
|
assertNotNull("Unable to parse variable", sources); //$NON-NLS-1$
|
||||||
|
assertTrue("Unable to parse \"main.cpp\" from SOURCES variable", sources.getValueIndex("main.cpp") == 0); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_SingleLineVariable_MultipleValues() {
|
||||||
|
IDocument document = new Document("CONFIG += qt debug"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
|
||||||
|
QtProjectVariable sources = parser.getVariable("CONFIG"); //$NON-NLS-1$
|
||||||
|
assertNotNull("Unable to parse variable", sources); //$NON-NLS-1$
|
||||||
|
assertTrue("Unable to parse \"qt debug\" from SOURCES variable", sources.getValueIndex("qt debug") == 0); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_VariableWithComment() {
|
||||||
|
IDocument document = new Document("SOURCES += main.cpp # this is a comment\n"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
|
||||||
|
QtProjectVariable sources = parser.getVariable("SOURCES"); //$NON-NLS-1$
|
||||||
|
assertNotNull("Unable to parse variable", sources); //$NON-NLS-1$
|
||||||
|
assertEquals("Unable to parse assignment from SOURCES variable", "+=", sources.getAssignmentOperator()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
assertTrue("Unable to parse \"main.cpp\" from SOURCES variable", sources.getValueIndex("main.cpp") == 0); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_MultilineVariable() {
|
||||||
|
IDocument document = new Document("SOURCES += main.cpp \\\n main2.cpp"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
|
||||||
|
QtProjectVariable sources = parser.getVariable("SOURCES"); //$NON-NLS-1$
|
||||||
|
assertNotNull("Unable to parse variable", sources); //$NON-NLS-1$
|
||||||
|
assertEquals("Incorrect number of lines", sources.getNumberOfLines(), 2); //$NON-NLS-1$
|
||||||
|
assertTrue("Unable to parse \"main.cpp\" from SOURCES variable", sources.getValueIndex("main.cpp") == 0); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
assertTrue("Unable to parse \"main2.cpp\" from SOURCES variable", sources.getValueIndex("main2.cpp") == 1); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_MultilineVariable2() {
|
||||||
|
IDocument document = new Document("SOURCES += main.cpp \\\n main2.cpp \\\n main3.cpp"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
|
||||||
|
QtProjectVariable sources = parser.getVariable("SOURCES"); //$NON-NLS-1$
|
||||||
|
assertNotNull("Unable to parse variable", sources); //$NON-NLS-1$
|
||||||
|
assertEquals("Incorrect number of lines", 3, sources.getNumberOfLines()); //$NON-NLS-1$
|
||||||
|
assertTrue("Unable to parse \"main.cpp\" from SOURCES variable", sources.getValueIndex("main.cpp") == 0); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
assertTrue("Unable to parse \"main2.cpp\" from SOURCES variable", sources.getValueIndex("main2.cpp") == 1); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
assertTrue("Unable to parse \"main3.cpp\" from SOURCES variable", sources.getValueIndex("main3.cpp") == 2); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_MalformedMultilineVariable() {
|
||||||
|
IDocument document = new Document("SOURCES += main.cpp \\\n main2.cpp \\"); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
|
||||||
|
QtProjectVariable sources = parser.getVariable("SOURCES"); //$NON-NLS-1$
|
||||||
|
assertNotNull("Unable to parse variable", sources); //$NON-NLS-1$
|
||||||
|
assertEquals("Incorrect number of lines", 2, sources.getNumberOfLines()); //$NON-NLS-1$
|
||||||
|
assertTrue("Unable to parse \"main.cpp\" from SOURCES variable", sources.getValueIndex("main.cpp") == 0); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
assertTrue("Unable to parse \"main2.cpp\" from SOURCES variable", sources.getValueIndex("main2.cpp") == 1); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_MultilineVariable_WithComment() {
|
||||||
|
IDocument document = new Document("SOURCES += main.cpp \\ # this is a comment \n main2.cpp # this is a comment "); //$NON-NLS-1$
|
||||||
|
QtProjectFileParser parser = new QtProjectFileParser(document);
|
||||||
|
|
||||||
|
QtProjectVariable sources = parser.getVariable("SOURCES"); //$NON-NLS-1$
|
||||||
|
assertNotNull("Unable to parse variable", sources); //$NON-NLS-1$
|
||||||
|
assertEquals("Incorrect number of lines", 2, sources.getNumberOfLines()); //$NON-NLS-1$
|
||||||
|
assertTrue("Unable to parse \"main.cpp\" from SOURCES variable", sources.getValueIndex("main.cpp") == 0); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
assertTrue("Unable to parse \"main2.cpp\" from SOURCES variable", sources.getValueIndex("main2.cpp") == 1); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,9 @@
|
||||||
*/
|
*/
|
||||||
package org.eclipse.cdt.qt.tests;
|
package org.eclipse.cdt.qt.tests;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.qt.pro.parser.tests.QtProjectFileModifierTest;
|
||||||
|
import org.eclipse.cdt.qt.pro.parser.tests.QtProjectFileParserTest;
|
||||||
|
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
@ -22,6 +25,8 @@ public class AllQtTests extends TestSuite {
|
||||||
QtContentAssistantTests.class,
|
QtContentAssistantTests.class,
|
||||||
QtIndexTests.class,
|
QtIndexTests.class,
|
||||||
QtRegressionTests.class,
|
QtRegressionTests.class,
|
||||||
QmlRegistrationTests.class);
|
QmlRegistrationTests.class,
|
||||||
|
QtProjectFileModifierTest.class,
|
||||||
|
QtProjectFileParserTest.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,4 +19,5 @@ Require-Bundle: org.eclipse.core.runtime,
|
||||||
org.eclipse.cdt.qt.core
|
org.eclipse.cdt.qt.core
|
||||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||||
Bundle-ActivationPolicy: lazy
|
Bundle-ActivationPolicy: lazy
|
||||||
Export-Package: org.eclipse.cdt.internal.qt.ui.assist;x-friends:="org.eclipse.cdt.qt.ui.tests"
|
Export-Package: org.eclipse.cdt.internal.qt.ui.assist;x-friends:="org.eclipse.cdt.qt.ui.tests",
|
||||||
|
org.eclipse.cdt.internal.qt.ui.pro.parser;x-friends:="org.eclipse.cdt.qt.ui.tests"
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
<editor
|
<editor
|
||||||
class="org.eclipse.cdt.internal.qt.ui.editor.QtProjectFileEditor"
|
class="org.eclipse.cdt.internal.qt.ui.editor.QtProjectFileEditor"
|
||||||
default="true"
|
default="true"
|
||||||
extensions="pro"
|
extensions="pro,pri"
|
||||||
id="org.eclipse.cdt.qt.ui.QtProjectFileEditor"
|
id="org.eclipse.cdt.qt.ui.QtProjectFileEditor"
|
||||||
name="%qtProjectFileEditor.name">
|
name="%qtProjectFileEditor.name">
|
||||||
</editor>
|
</editor>
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
package org.eclipse.cdt.internal.qt.ui;
|
package org.eclipse.cdt.internal.qt.ui;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.model.CModelException;
|
import org.eclipse.cdt.core.model.CModelException;
|
||||||
|
import org.eclipse.cdt.internal.qt.ui.resources.QtResourceChangeListener;
|
||||||
|
import org.eclipse.cdt.internal.qt.ui.resources.QtWorkspaceSaveParticipant;
|
||||||
|
import org.eclipse.core.resources.ISaveParticipant;
|
||||||
|
import org.eclipse.core.resources.ISavedState;
|
||||||
|
import org.eclipse.core.resources.ResourcesPlugin;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
import org.eclipse.core.runtime.IStatus;
|
import org.eclipse.core.runtime.IStatus;
|
||||||
import org.eclipse.core.runtime.Status;
|
import org.eclipse.core.runtime.Status;
|
||||||
|
@ -44,6 +49,15 @@ public class QtUIPlugin extends AbstractUIPlugin {
|
||||||
public void start(BundleContext context) throws Exception {
|
public void start(BundleContext context) throws Exception {
|
||||||
super.start(context);
|
super.start(context);
|
||||||
plugin = this;
|
plugin = this;
|
||||||
|
|
||||||
|
// Use a save participant to grab any changed resources while this plugin was inactive
|
||||||
|
QtResourceChangeListener resourceManager = new QtResourceChangeListener();
|
||||||
|
ISaveParticipant saveParticipant = new QtWorkspaceSaveParticipant();
|
||||||
|
ISavedState lastState = ResourcesPlugin.getWorkspace().addSaveParticipant(QtUIPlugin.PLUGIN_ID, saveParticipant);
|
||||||
|
if (lastState != null) {
|
||||||
|
lastState.processResourceChangeEvents(resourceManager);
|
||||||
|
}
|
||||||
|
ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,286 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* QNX Software Systems - Initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.qt.ui.pro.parser;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.qt.core.QtPlugin;
|
||||||
|
import org.eclipse.jface.text.BadLocationException;
|
||||||
|
import org.eclipse.jface.text.IDocument;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows for the manipulation of information stored in a Qt Project File. At the moment the only modifiable information is that
|
||||||
|
* which is contained within variables such as the following:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* <code>SOURCES += file.cpp \ # This is the first line with value "file.cpp"
|
||||||
|
* file2.cpp # This is the second line with value "file2.cpp"</code>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* This class supports the following modifications to variables:
|
||||||
|
* <ul>
|
||||||
|
* <li><b>Add Value</b>: If the specified String does not exist in the given variable then it is added as a new line at the end of
|
||||||
|
* the variable declaration. A line escape (\) is also inserted into the preceding line.</li>
|
||||||
|
* <li><b>Remove Value</b>: If the specified String exists in the given variable then it is removed. The line escape character (\)
|
||||||
|
* is also removed from the preceding line if necessary.</li>
|
||||||
|
* <li><b>Replace Value</b>: If the specified String exists as a line in the given variable, then it is replaced with another
|
||||||
|
* String. All spacing is preserved as only the value itself is modified.</li>
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* Comments may appear after the line escape character (\) in a variable Declaration. For this case, replace and addition operations
|
||||||
|
* will preserve these comments. However, a comment will not be preserved if its line is deleted during a remove operation.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class QtProjectFileModifier {
|
||||||
|
|
||||||
|
private QtProjectFileParser parser;
|
||||||
|
private IDocument document;
|
||||||
|
|
||||||
|
public QtProjectFileModifier(IDocument doc) {
|
||||||
|
if (doc == null) {
|
||||||
|
throw new IllegalArgumentException("document cannot be null"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
this.document = doc;
|
||||||
|
this.parser = new QtProjectFileParser(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QtProjectFileModifier(QtProjectFileParser parser) {
|
||||||
|
if (parser == null) {
|
||||||
|
throw new IllegalArgumentException("parser cannot be null"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
this.document = parser.getDocument();
|
||||||
|
this.parser = parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to replace the given value with a new value if it is found within the given variable name. This is a convenience
|
||||||
|
* method equivalent to <code>replaceVariableValue(variable,oldValue,newValue,true)</code> and will only match values that
|
||||||
|
* occupy an entire line within the variable declaration.
|
||||||
|
* <p>
|
||||||
|
* This method does <b>not</b> create a new value if the specified <code>oldValue</code> was not found. If this behavior is
|
||||||
|
* desired, then check for a return of <code>false</code> from this method and then call the <code>addVariableValue</code>
|
||||||
|
* method.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* <b>Note:</b> The "entire line" refers to only the value as it appears in the variable declaration. That is, any whitespace
|
||||||
|
* before or after will not be included when matching a value to the "entire line".
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param variable
|
||||||
|
* the name of the variable
|
||||||
|
* @param oldValue
|
||||||
|
* the value that will be replaced
|
||||||
|
* @param newValue
|
||||||
|
* the value to replace with
|
||||||
|
* @return whether or not the value was able to be replaced
|
||||||
|
*/
|
||||||
|
public boolean replaceVariableValue(String variable, String oldValue, String newValue) {
|
||||||
|
return replaceVariableValue(variable, oldValue, newValue, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to replace the first instance of <code>oldValue</code> with <code>newValue</code> if it is found within the given
|
||||||
|
* variable name. If <code>matchWholeLine</code> is false, this method will try to match sections of each line with the value of
|
||||||
|
* <code>oldValue</code>. If a match is found, only that portion of the line will be replaced. If <code>matchWholeLine</code> is
|
||||||
|
* true, this method will try to match the entire line with the value of <code>oldValue</code> and will replace that. All other
|
||||||
|
* line spacing and comments are preserved as only the value itself is replaced.
|
||||||
|
* <p>
|
||||||
|
* This method does <b>not</b> create a new value if <code>oldValue</code> was not found. If this behavior is desired, then
|
||||||
|
* check for a return of <code>false</code> from this method and then call the <code>addVariableValue</code> method.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* <b>Note:</b> The "entire line" refers to only the value as it appears in the variable declaration. That is, any whitespace
|
||||||
|
* before or after will not be included when matching a value to the "entire line".
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param variable
|
||||||
|
* the name of the variable
|
||||||
|
* @param oldValue
|
||||||
|
* the value that will be replaced
|
||||||
|
* @param newValue
|
||||||
|
* the value to replace with
|
||||||
|
* @param matchWholeLine
|
||||||
|
* whether or not the value should match the entire line
|
||||||
|
* @return whether or not the value was able to be replaced
|
||||||
|
*/
|
||||||
|
public boolean replaceVariableValue(String variable, String oldValue, String newValue, boolean matchWholeLine) {
|
||||||
|
QtProjectVariable var = parser.getVariable(variable);
|
||||||
|
|
||||||
|
if (var != null) {
|
||||||
|
if (matchWholeLine) {
|
||||||
|
int line = var.getValueIndex(oldValue);
|
||||||
|
if (line >= 0) {
|
||||||
|
return replaceVariableValue(var, line, newValue);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int line = 0;
|
||||||
|
for (String value : var.getValues()) {
|
||||||
|
int offset = value.indexOf(oldValue);
|
||||||
|
if (offset >= 0) {
|
||||||
|
return replaceVariableValue(var,
|
||||||
|
line,
|
||||||
|
var.getValueOffsetForLine(line) + offset,
|
||||||
|
oldValue.length(),
|
||||||
|
newValue);
|
||||||
|
}
|
||||||
|
line++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean replaceVariableValue(QtProjectVariable var, int lineNo, String newValue) {
|
||||||
|
int offset = var.getValueOffsetForLine(lineNo);
|
||||||
|
String value = var.getValueForLine(lineNo);
|
||||||
|
int length = value.length();
|
||||||
|
|
||||||
|
return replaceVariableValue(var, lineNo, offset, length, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean replaceVariableValue(QtProjectVariable var, int lineNo, int offset, int length, String newValue) {
|
||||||
|
try {
|
||||||
|
document.replace(offset, length, newValue);
|
||||||
|
return true;
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
QtPlugin.log(e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds <code>value</code> to the specified variable as a new line and escapes the previous line with a backslash. The escaping
|
||||||
|
* is done in such a way that comments and spacing are preserved on the previous line. If this variable does not exist, a new
|
||||||
|
* one is created at the bottom-most position of the document with the initial value specified by <code>value</code>.
|
||||||
|
*
|
||||||
|
* @param variable
|
||||||
|
* the name of the variable to add to
|
||||||
|
* @param value
|
||||||
|
* the value to add to the variable
|
||||||
|
*/
|
||||||
|
public void addVariableValue(String variable, String value) {
|
||||||
|
QtProjectVariable var = parser.getVariable(variable);
|
||||||
|
|
||||||
|
if (var != null) {
|
||||||
|
if (var.getValueIndex(value) < 0) {
|
||||||
|
int line = var.getNumberOfLines() - 1;
|
||||||
|
String indent = var.getIndentString(line);
|
||||||
|
|
||||||
|
int offset = var.getEndOffset();
|
||||||
|
if (var.getLine(line).endsWith("\n")) { //$NON-NLS-1$
|
||||||
|
offset--;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
document.replace(offset, 0, "\n" + indent + value); //$NON-NLS-1$
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
QtPlugin.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
offset = var.getLineEscapeReplacementOffset(line);
|
||||||
|
String lineEscape = var.getLineEscapeReplacementString(line);
|
||||||
|
|
||||||
|
document.replace(offset, 0, lineEscape);
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
QtPlugin.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Variable does not exist, create it
|
||||||
|
String baseVariable = variable + " += " + value + "\n"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
// Check the contents of the document and re-format accordingly
|
||||||
|
if (document.get().trim().isEmpty()) {
|
||||||
|
try {
|
||||||
|
document.replace(0, document.getLength(), baseVariable);
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
QtPlugin.log(e);
|
||||||
|
}
|
||||||
|
} else if (document.get().endsWith("\n")) { //$NON-NLS-1$
|
||||||
|
try {
|
||||||
|
document.replace(document.getLength(), 0, "\n" + baseVariable); //$NON-NLS-1$
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
QtPlugin.log(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
document.replace(document.getLength(), 0, "\n\n" + baseVariable); //$NON-NLS-1$
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
QtPlugin.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes <code>value</code> from the specified variable and removes the previous line escape if necessary. The entire line is
|
||||||
|
* removed including any comments. If the value is not found, nothing happens.
|
||||||
|
*
|
||||||
|
* @param variable
|
||||||
|
* the name of the variable to remove from
|
||||||
|
* @param value
|
||||||
|
* the value to remove from the variable
|
||||||
|
*/
|
||||||
|
public void removeVariableValue(String variable, String value) {
|
||||||
|
QtProjectVariable var = parser.getVariable(variable);
|
||||||
|
|
||||||
|
if (var != null) {
|
||||||
|
int line = var.getValueIndex(value);
|
||||||
|
if (line == 0 && var.getNumberOfLines() > 1) {
|
||||||
|
// Entering this block means we're removing the first line where more lines exist.
|
||||||
|
int offset = var.getValueOffsetForLine(line);
|
||||||
|
int end = var.getValueOffsetForLine(line + 1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
document.replace(offset, end - offset, ""); //$NON-NLS-1$
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
QtPlugin.log(e);
|
||||||
|
}
|
||||||
|
} else if (line >= 0) {
|
||||||
|
int offset = var.getLineOffset(line);
|
||||||
|
int length = var.getLine(line).length();
|
||||||
|
if (line > 0) {
|
||||||
|
// Remove the previous line feed character
|
||||||
|
offset--;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
document.replace(offset, length, ""); //$NON-NLS-1$
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
QtPlugin.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the previous line's line escape character if necessary
|
||||||
|
if (line > 0 && line == var.getNumberOfLines() - 1) {
|
||||||
|
try {
|
||||||
|
offset = var.getLineEscapeOffset(line - 1);
|
||||||
|
length = var.getLineEscapeEnd(line - 1) - offset;
|
||||||
|
|
||||||
|
document.replace(offset, length, ""); //$NON-NLS-1$
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
QtPlugin.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the <code>IDocument</code> currently being modified by this class.
|
||||||
|
*
|
||||||
|
* @return the document being modified
|
||||||
|
*/
|
||||||
|
public IDocument getDocument() {
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* QNX Software Systems - Initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.qt.ui.pro.parser;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
import org.eclipse.jface.text.DocumentEvent;
|
||||||
|
import org.eclipse.jface.text.IDocument;
|
||||||
|
import org.eclipse.jface.text.IDocumentListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Very basic parser for Qt Project Files that uses regular expressions. For now, this class only supports finding variables within
|
||||||
|
* a Document that follow the syntax:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* <code>VARIABLE_NAME += value1 \ # comment
|
||||||
|
* value2 \ # comment
|
||||||
|
* value3</code>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* The assignment operator may be one of =, +=, -=, or *= in accordance with qmake syntax. Variable names are not checked for
|
||||||
|
* semantic validity. That is, this class does not make sure the variable name is a registered qmake variable, nor that there are
|
||||||
|
* multiple instances of a variable in the document.
|
||||||
|
*/
|
||||||
|
public class QtProjectFileParser implements IDocumentListener {
|
||||||
|
|
||||||
|
IDocument document;
|
||||||
|
List<QtProjectVariable> variables;
|
||||||
|
|
||||||
|
public QtProjectFileParser(IDocument doc) {
|
||||||
|
if (doc == null) {
|
||||||
|
throw new IllegalArgumentException("document cannot be null"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
document = doc;
|
||||||
|
variables = parse();
|
||||||
|
document.addDocumentListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDocument getDocument() {
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<QtProjectVariable> parse() {
|
||||||
|
// Just build the list from scratch
|
||||||
|
List<QtProjectVariable> variables = new CopyOnWriteArrayList<>();
|
||||||
|
try (Scanner scanner = new Scanner(document.get())) {
|
||||||
|
QtProjectVariable next;
|
||||||
|
while ((next = QtProjectVariable.findNextVariable(scanner)) != null) {
|
||||||
|
variables.add(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a specific Qt Project Variable from the provided <code>IDocument</code>. If the variable cannot be found,
|
||||||
|
* <code>null</code> is returned instead.
|
||||||
|
* <p>
|
||||||
|
* <b>Note:</b> This method is greedy in the sense that it returns the first match it finds. If multiple variables exist with
|
||||||
|
* the same name in the <code>IDocument</code>, this method will only return the first match.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the name of the variable
|
||||||
|
* @return the <code>QtProjectVariable</code> or <code>null</code> if it couldn't be found
|
||||||
|
*/
|
||||||
|
public QtProjectVariable getVariable(String name) {
|
||||||
|
for (QtProjectVariable v : variables) {
|
||||||
|
if (v.getName().equals(name)) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all Qt Project Variables found within the provided <code>IDocument</code>. A fresh list is always returned
|
||||||
|
* with the internal list copied into it. As such, modifying this list does not modify the internal list of the parser.
|
||||||
|
*
|
||||||
|
* @return the list of all Qt Project Variables
|
||||||
|
*/
|
||||||
|
public List<QtProjectVariable> getAllVariables() {
|
||||||
|
return new ArrayList<>(variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void documentAboutToBeChanged(DocumentEvent event) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void documentChanged(DocumentEvent event) {
|
||||||
|
// Re-parse the document every time it changes
|
||||||
|
variables = parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
// Make sure that we are removed from the document's listeners
|
||||||
|
if (document != null) {
|
||||||
|
document.removeDocumentListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,389 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* QNX Software Systems - Initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.qt.ui.pro.parser;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.regex.MatchResult;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains all information about a variable's representation in a Qt Project (.pro) File. This includes information about offsets,
|
||||||
|
* lengths, and textual representation of various components of a variable declaration such as its:
|
||||||
|
* <ul>
|
||||||
|
* <li>Name, such as "SOURCES"</li>
|
||||||
|
* <li>Assignment operator (= or +=)</li>
|
||||||
|
* <li>Values for a particular line</li>
|
||||||
|
* <li>Comments for a particular line</li>
|
||||||
|
* <li>Line feeds</li>
|
||||||
|
* <li>Line escapes (\)</li>
|
||||||
|
* </ul>
|
||||||
|
* Also contains the static method <code>findNextVariable(Scanner)</code> to perform the regular expressions lookup of the next
|
||||||
|
* variable in a document.
|
||||||
|
*/
|
||||||
|
public class QtProjectVariable {
|
||||||
|
private static final Pattern REGEX = Pattern.compile(
|
||||||
|
"(?m)^\\h*((?:[_a-zA-Z][_a-zA-Z0-9]*\\.)*[_a-zA-Z][_a-zA-Z0-9]*)\\h*(=|\\+=|-=|\\*=)\\h*([^#\\v]*?)\\h*((?:(\\\\)\\h*)?(#[^\\v]*)?$)"); //$NON-NLS-1$
|
||||||
|
private static final Pattern LINE_ESCAPE_REGEX = Pattern.compile("(?m)^(\\h*)([^#\\v]*?)\\h*((?:(\\\\)\\h*)?(#[^\\v]*)?$)"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
private static final int GROUP_VAR_NAME = 1;
|
||||||
|
private static final int GROUP_VAR_ASSIGNMENT = 2;
|
||||||
|
private static final int GROUP_VAR_CONTENTS = 3;
|
||||||
|
private static final int GROUP_VAR_TERMINATOR = 4;
|
||||||
|
private static final int GROUP_VAR_LINE_ESCAPE = 5;
|
||||||
|
private static final int GROUP_VAR_COMMENT = 6;
|
||||||
|
|
||||||
|
private static final int GROUP_LINE_INDENT = 1;
|
||||||
|
private static final int GROUP_LINE_CONTENTS = 2;
|
||||||
|
private static final int GROUP_LINE_TERMINATOR = 3;
|
||||||
|
private static final int GROUP_LINE_LINE_ESCAPE = 4;
|
||||||
|
private static final int GROUP_LINE_COMMENT = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the next Qt Project Variable within a String using the given Scanner. If there are no variables to be found, this
|
||||||
|
* method will return <code>null</code>.
|
||||||
|
*
|
||||||
|
* @param scanner
|
||||||
|
* the scanner to use for regular expressions matching
|
||||||
|
* @return the next variable or <code>null</code> if none
|
||||||
|
*/
|
||||||
|
public static QtProjectVariable findNextVariable(Scanner scanner) {
|
||||||
|
List<MatchResult> matchResults = new ArrayList<>();
|
||||||
|
|
||||||
|
// Find the start of a variable declaration
|
||||||
|
String match = scanner.findWithinHorizon(REGEX, 0);
|
||||||
|
if (match == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get subsequent lines if the previous one ends with '\'
|
||||||
|
MatchResult matchResult = scanner.match();
|
||||||
|
matchResults.add(matchResult);
|
||||||
|
if (matchResult.group(QtProjectVariable.GROUP_VAR_TERMINATOR).startsWith("\\")) { //$NON-NLS-1$
|
||||||
|
do {
|
||||||
|
match = scanner.findWithinHorizon(LINE_ESCAPE_REGEX, 0);
|
||||||
|
if (match == null) {
|
||||||
|
// This means that we have a newline escape where another line doesn't exist
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
matchResult = scanner.match();
|
||||||
|
matchResults.add(matchResult);
|
||||||
|
} while (matchResult.group(QtProjectVariable.GROUP_LINE_TERMINATOR).startsWith("\\")); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
return new QtProjectVariable(matchResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int startOffset;
|
||||||
|
private final int endOffset;
|
||||||
|
private final String text;
|
||||||
|
|
||||||
|
private final List<MatchResult> matchResults;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a project file variable from a list of match results obtained from a <code>Scanner</code>. This constructor is
|
||||||
|
* only intended to be called from within the static method <code>findNextVariable(Scanner)</code>.
|
||||||
|
*
|
||||||
|
* @param matches
|
||||||
|
* list of <code>MatchResult</code>
|
||||||
|
*/
|
||||||
|
private QtProjectVariable(List<MatchResult> matches) {
|
||||||
|
this.startOffset = matches.get(0).start();
|
||||||
|
this.endOffset = matches.get(matches.size() - 1).end();
|
||||||
|
this.matchResults = matches;
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (MatchResult m : matches) {
|
||||||
|
sb.append(m.group());
|
||||||
|
}
|
||||||
|
this.text = sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the offset of this variable relative to the start of its containing document.
|
||||||
|
*
|
||||||
|
* @return the offset of this variable
|
||||||
|
*/
|
||||||
|
public int getOffset() {
|
||||||
|
return startOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the length of this variable as it appears in its containing document.
|
||||||
|
*
|
||||||
|
* @return the total length of this variable
|
||||||
|
*/
|
||||||
|
public int getLength() {
|
||||||
|
return endOffset - startOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of this variable as it appears in the document. For example, the <code>"SOURCES"</code> variable.
|
||||||
|
*
|
||||||
|
* @return the name of this variable
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return matchResults.get(0).group(GROUP_VAR_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the assignment operator of this variable (<code>+=</code> or <code>"="</code>)
|
||||||
|
*
|
||||||
|
* @return the assignment operator
|
||||||
|
*/
|
||||||
|
public String getAssignmentOperator() {
|
||||||
|
return matchResults.get(0).group(GROUP_VAR_ASSIGNMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of value(s) assigned to this variable. Each entry in the list represents a new line.
|
||||||
|
*
|
||||||
|
* @return a List containing all of the value(s) assigned to this variable
|
||||||
|
*/
|
||||||
|
public List<String> getValues() {
|
||||||
|
List<String> values = new ArrayList<String>();
|
||||||
|
values.add(matchResults.get(0).group(GROUP_VAR_CONTENTS));
|
||||||
|
for (int i = 1; i < matchResults.size(); i++) {
|
||||||
|
values.add(matchResults.get(i).group(GROUP_LINE_CONTENTS));
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the indentation of the given line as a String. Mainly used by the QtProjectFileWriter to write back to the Document.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* the line number to check
|
||||||
|
* @return a <code>String</code> representing the indentation of the given line
|
||||||
|
*/
|
||||||
|
public String getIndentString(int line) {
|
||||||
|
MatchResult match = matchResults.get(line);
|
||||||
|
if (line == 0) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < match.start(GROUP_VAR_CONTENTS) - match.start(); i++) {
|
||||||
|
sb.append(' ');
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
return match.group(GROUP_LINE_INDENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the offset of the value portion of a given line relative to the start of its containing document.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* the line to check
|
||||||
|
* @return the offset of the value
|
||||||
|
*/
|
||||||
|
public int getValueOffsetForLine(int line) {
|
||||||
|
if (line == 0) {
|
||||||
|
return matchResults.get(line).start(GROUP_VAR_CONTENTS);
|
||||||
|
}
|
||||||
|
return matchResults.get(line).start(GROUP_LINE_CONTENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a String representing the value at a specific line of this variable.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* the line to check
|
||||||
|
* @return the value
|
||||||
|
*/
|
||||||
|
public String getValueForLine(int line) {
|
||||||
|
if (line == 0) {
|
||||||
|
return matchResults.get(line).group(GROUP_VAR_CONTENTS);
|
||||||
|
}
|
||||||
|
return matchResults.get(line).group(GROUP_LINE_CONTENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ideal offset in the containing document at which a line escape can be inserted.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* the line to check
|
||||||
|
* @return the ideal location for a line escape
|
||||||
|
*/
|
||||||
|
public int getLineEscapeReplacementOffset(int line) {
|
||||||
|
if (line == 0) {
|
||||||
|
return matchResults.get(line).end(GROUP_VAR_CONTENTS);
|
||||||
|
}
|
||||||
|
return matchResults.get(line).end(GROUP_LINE_CONTENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ideal String for the line escape character. This is mostly for spacing requirements and should be used in tandem
|
||||||
|
* with the method <code>getLineEscapeReplacementOffset</code>.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* the line to check
|
||||||
|
* @return the ideal String for the line escape character
|
||||||
|
*/
|
||||||
|
public String getLineEscapeReplacementString(int line) {
|
||||||
|
int commentOffset = -1;
|
||||||
|
int contentsOffset = -1;
|
||||||
|
if (line == 0) {
|
||||||
|
commentOffset = matchResults.get(line).start(GROUP_VAR_COMMENT);
|
||||||
|
contentsOffset = matchResults.get(line).end(GROUP_VAR_CONTENTS);
|
||||||
|
} else {
|
||||||
|
commentOffset = matchResults.get(line).start(GROUP_LINE_COMMENT);
|
||||||
|
contentsOffset = matchResults.get(line).end(GROUP_LINE_CONTENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commentOffset > 0) {
|
||||||
|
if (commentOffset - contentsOffset == 0) {
|
||||||
|
return " \\ "; //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return " \\"; //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the offset of the line escape for a given line relative to its containing document. This method takes into account
|
||||||
|
* spacing and should be used to determine how to best remove a line escape character from a given line.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* the line to check
|
||||||
|
* @return the offset of the line escape character
|
||||||
|
*/
|
||||||
|
public int getLineEscapeOffset(int line) {
|
||||||
|
if (line == 0) {
|
||||||
|
return matchResults.get(line).end(GROUP_VAR_CONTENTS);
|
||||||
|
}
|
||||||
|
return matchResults.get(line).end(GROUP_LINE_CONTENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the end position relative to the start of the containing document that contains the line escape character of the given
|
||||||
|
* line. This is used for removal of the line escape character and takes into account the spacing of the line.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* the line to check
|
||||||
|
* @return the end position of the line escape character
|
||||||
|
*/
|
||||||
|
public int getLineEscapeEnd(int line) {
|
||||||
|
int end = -1;
|
||||||
|
if (line == 0) {
|
||||||
|
end = matchResults.get(line).end(GROUP_VAR_LINE_ESCAPE);
|
||||||
|
} else {
|
||||||
|
end = matchResults.get(line).end(GROUP_LINE_LINE_ESCAPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end > 0) {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == 0) {
|
||||||
|
return matchResults.get(line).end(GROUP_VAR_TERMINATOR);
|
||||||
|
}
|
||||||
|
return matchResults.get(line).end(GROUP_LINE_TERMINATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the end position of this variable relative to the containing document.
|
||||||
|
*
|
||||||
|
* @return the end position of this variable
|
||||||
|
*/
|
||||||
|
public int getEndOffset() {
|
||||||
|
return matchResults.get(matchResults.size() - 1).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the full text of this variable as it appears in the document.
|
||||||
|
*
|
||||||
|
* @return the full String of this variable as it appears in the document
|
||||||
|
*/
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the total number of lines in this variable declaration.
|
||||||
|
*
|
||||||
|
* @return the total number of lines
|
||||||
|
*/
|
||||||
|
public int getNumberOfLines() {
|
||||||
|
return matchResults.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a String representing the given line as it appears in the document.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* the line to retrieve
|
||||||
|
* @return a String representing the line
|
||||||
|
*/
|
||||||
|
public String getLine(int line) {
|
||||||
|
return matchResults.get(line).group();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the offset of the given line relative to its containing document.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* the line to retrieve
|
||||||
|
* @return the line's offset in the document
|
||||||
|
*/
|
||||||
|
public int getLineOffset(int line) {
|
||||||
|
return matchResults.get(line).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the line at which the specified value appears. This method checks the whole line for the value and will not match a
|
||||||
|
* subset of that String. This is equivalent to calling <code>getValueIndex(value,false)</code>.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* the value to search for
|
||||||
|
* @return the line that the value appears on or -1 if it doesn't exist
|
||||||
|
*/
|
||||||
|
public int getValueIndex(String value) {
|
||||||
|
return getValueIndex(value, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the line at which the specified value appears. This method checks the whole line for the value and will not match a
|
||||||
|
* subset of that String. If <code>ignoreCase</code> is <code>false</code>, this method searches for the value using
|
||||||
|
* <code>equalsIgnoreCase</code> instead of <code>equals</code>.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* the value to search for
|
||||||
|
* @param ignoreCase
|
||||||
|
* whether or not the value is case-sensitive
|
||||||
|
* @return the line that the value appears on or -1 if it doesn't exist
|
||||||
|
*/
|
||||||
|
public int getValueIndex(String value, boolean ignoreCase) {
|
||||||
|
int line = 0;
|
||||||
|
for (String val : getValues()) {
|
||||||
|
if (ignoreCase) {
|
||||||
|
if (val.equalsIgnoreCase(value)) {
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (val.equals(value)) {
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line++;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the offset of the end of a given line relative to its containing document.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* the line to check
|
||||||
|
* @return the offset of the end of the line
|
||||||
|
*/
|
||||||
|
public int getLineEnd(int line) {
|
||||||
|
return matchResults.get(line).end();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* QNX Software Systems - Initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.qt.ui.resources;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.qt.ui.QtUIPlugin;
|
||||||
|
import org.eclipse.cdt.internal.qt.ui.editor.QtProjectFileKeyword;
|
||||||
|
import org.eclipse.cdt.internal.qt.ui.pro.parser.QtProjectFileModifier;
|
||||||
|
import org.eclipse.core.resources.IFile;
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
|
import org.eclipse.core.resources.IResource;
|
||||||
|
import org.eclipse.core.resources.IResourceDelta;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.core.runtime.jobs.Job;
|
||||||
|
import org.eclipse.jface.text.Document;
|
||||||
|
import org.eclipse.jface.text.IDocument;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Job that calls the <code>QtProjectFileModifier</code> after changes to resources found in Qt Projects in order to update their
|
||||||
|
* <code>SOURCES</code> variable.
|
||||||
|
*/
|
||||||
|
public class QtProjectFileUpdateJob extends Job {
|
||||||
|
|
||||||
|
private List<IResourceDelta> deltaList;
|
||||||
|
|
||||||
|
public QtProjectFileUpdateJob(List<IResourceDelta> deltas) {
|
||||||
|
super("Update Qt Project File(s)"); //$NON-NLS-1$
|
||||||
|
this.deltaList = deltas;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IFile findQtProjectFile(IProject project) throws CoreException {
|
||||||
|
for (IResource member : project.members()) {
|
||||||
|
if (member.getType() == IResource.FILE
|
||||||
|
&& member.getFileExtension().equals("pro")) { //$NON-NLS-1$
|
||||||
|
return (IFile) member;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IStatus run(IProgressMonitor monitor) {
|
||||||
|
// Cache the project files so we don't continuously open them
|
||||||
|
Map<IProject, QtProjectFileModifier> modifierMap = new HashMap<>();
|
||||||
|
Map<IProject, IFile> projectFileMap = new HashMap<>();
|
||||||
|
|
||||||
|
for (IResourceDelta delta : deltaList) {
|
||||||
|
IResource resource = delta.getResource();
|
||||||
|
IProject project = resource.getProject();
|
||||||
|
QtProjectFileModifier modifier = modifierMap.get(project);
|
||||||
|
|
||||||
|
if (modifier == null) {
|
||||||
|
IFile proFile = null;
|
||||||
|
try {
|
||||||
|
proFile = findQtProjectFile(project);
|
||||||
|
} catch (CoreException e) {
|
||||||
|
QtUIPlugin.log("Unable to find Qt Project File", e); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't update a project file if it doesn't exist
|
||||||
|
if (proFile == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache the project file under its containing project and read its contents into a Document.
|
||||||
|
projectFileMap.put(project, proFile);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
try (InputStream is = proFile.getContents()) {
|
||||||
|
int read = -1;
|
||||||
|
while ((read = is.read()) > 0) {
|
||||||
|
sb.append((char) read);
|
||||||
|
}
|
||||||
|
IDocument document = new Document(sb.toString());
|
||||||
|
modifier = new QtProjectFileModifier(document);
|
||||||
|
modifierMap.put(project, modifier);
|
||||||
|
} catch (IOException e) {
|
||||||
|
QtUIPlugin.log(e);
|
||||||
|
break;
|
||||||
|
} catch (CoreException e) {
|
||||||
|
QtUIPlugin.log(e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine from the file extension where we should add this resource
|
||||||
|
String variableKeyword = null;
|
||||||
|
if ("cpp".equals(resource.getFileExtension())) { //$NON-NLS-1$
|
||||||
|
variableKeyword = QtProjectFileKeyword.VAR_SOURCES.getKeyword();
|
||||||
|
} else if ("h".equals(resource.getFileExtension())) { //$NON-NLS-1$
|
||||||
|
variableKeyword = QtProjectFileKeyword.VAR_HEADERS.getKeyword();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((delta.getFlags() & IResourceDelta.MOVED_FROM) > 0) {
|
||||||
|
// Resource was moved from another location.
|
||||||
|
if (project.getFullPath().isPrefixOf(delta.getMovedFromPath())) {
|
||||||
|
String oldValue = delta.getMovedFromPath().makeRelativeTo(project.getFullPath()).toString();
|
||||||
|
String newValue = resource.getProjectRelativePath().toString();
|
||||||
|
|
||||||
|
if (modifier.replaceVariableValue(variableKeyword, oldValue, newValue)) {
|
||||||
|
// If we successfully replaced the variable, continue. If this line is not executed it means we failed to
|
||||||
|
// replace and the file will be added in the subsequent code for the ADDED case.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((delta.getFlags() & IResourceDelta.MOVED_TO) > 0) {
|
||||||
|
// Somewhat edge-case where a file from one Qt Project was moved to a different Qt Project.
|
||||||
|
if (project.getFullPath().isPrefixOf(delta.getMovedToPath())) {
|
||||||
|
// Getting here means that the replace was taken care of by the previous code. Otherwise, it will be removed in
|
||||||
|
// the subsequent code for the REMOVED case.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((delta.getKind() & IResourceDelta.ADDED) > 0) {
|
||||||
|
String value = resource.getProjectRelativePath().toString();
|
||||||
|
if (value != null) {
|
||||||
|
modifier.addVariableValue(variableKeyword, value);
|
||||||
|
}
|
||||||
|
} else if ((delta.getKind() & IResourceDelta.REMOVED) > 0) {
|
||||||
|
String value = resource.getProjectRelativePath().toString();
|
||||||
|
if (value != null) {
|
||||||
|
modifier.removeVariableValue(variableKeyword, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write all documents to their respective files
|
||||||
|
for (IProject project : projectFileMap.keySet()) {
|
||||||
|
IFile file = projectFileMap.get(project);
|
||||||
|
IDocument document = modifierMap.get(project).getDocument();
|
||||||
|
|
||||||
|
try {
|
||||||
|
file.setContents(new ByteArrayInputStream(document.get().getBytes()), 0, null);
|
||||||
|
} catch (CoreException e) {
|
||||||
|
QtUIPlugin.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* QNX Software Systems - Initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.qt.ui.resources;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.qt.core.QtNature;
|
||||||
|
import org.eclipse.cdt.internal.qt.ui.QtUIPlugin;
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
|
import org.eclipse.core.resources.IResource;
|
||||||
|
import org.eclipse.core.resources.IResourceChangeEvent;
|
||||||
|
import org.eclipse.core.resources.IResourceChangeListener;
|
||||||
|
import org.eclipse.core.resources.IResourceDelta;
|
||||||
|
import org.eclipse.core.resources.IResourceDeltaVisitor;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects the addition or removal of a file to a Qt project. If one of these resource changes is found, it triggers an update of
|
||||||
|
* the project's *.pro file to reflect the change.
|
||||||
|
*/
|
||||||
|
public class QtResourceChangeListener implements IResourceChangeListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resourceChanged(IResourceChangeEvent event) {
|
||||||
|
// No need to check for any events other than POST_CHANGE
|
||||||
|
if ((event.getType() & (IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.POST_BUILD)) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<IResourceDelta> deltaList = new ArrayList<>();
|
||||||
|
IResourceDeltaVisitor visitor = new IResourceDeltaVisitor() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visit(IResourceDelta delta) {
|
||||||
|
IResource resource = delta.getResource();
|
||||||
|
|
||||||
|
if (resource.getType() == IResource.ROOT) {
|
||||||
|
// Always traverse children of the workspace root
|
||||||
|
return true;
|
||||||
|
} else if (resource.getType() == IResource.PROJECT) {
|
||||||
|
// Only traverse children of Qt Projects
|
||||||
|
try {
|
||||||
|
IProject project = (IProject) resource;
|
||||||
|
if (project.hasNature(QtNature.ID)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (CoreException e) {
|
||||||
|
QtUIPlugin.log(e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (resource.getType() == IResource.FOLDER) {
|
||||||
|
// First, make sure this isn't the "build" folder
|
||||||
|
if (resource.getType() == IResource.FOLDER) {
|
||||||
|
if (resource.getName().equals("build")) { //$NON-NLS-1$
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then check to make sure that the folder lies in a Qt Project
|
||||||
|
try {
|
||||||
|
IProject project = resource.getProject();
|
||||||
|
if (project != null && project.hasNature(QtNature.ID)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (CoreException e) {
|
||||||
|
QtUIPlugin.log(e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only care about added and removed resources at this point
|
||||||
|
if ((delta.getKind() & (IResourceDelta.ADDED | IResourceDelta.REMOVED)) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("cpp".equals(resource.getFileExtension()) //$NON-NLS-1$
|
||||||
|
|| "h".equals(resource.getFileExtension())) { //$NON-NLS-1$
|
||||||
|
// If we make it to this point, then we have a .cpp or .h file that's been added to or removed from a Qt
|
||||||
|
// Project. Add it to the list of deltas so we can update the project file later.
|
||||||
|
deltaList.add(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Doesn't really matter since this line can only be reached if we're dealing with a file that shouldn't have
|
||||||
|
// children anyway
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check all projects starting at the workspace root
|
||||||
|
event.getDelta().accept(visitor);
|
||||||
|
} catch (CoreException e) {
|
||||||
|
QtUIPlugin.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule the job to update the .pro files
|
||||||
|
if (!deltaList.isEmpty()) {
|
||||||
|
new QtProjectFileUpdateJob(deltaList).schedule();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* QNX Software Systems - Initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.qt.ui.resources;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.ISaveContext;
|
||||||
|
import org.eclipse.core.resources.ISaveParticipant;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
|
||||||
|
public class QtWorkspaceSaveParticipant implements ISaveParticipant {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doneSaving(ISaveContext context) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void prepareToSave(ISaveContext context) throws CoreException {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rollback(ISaveContext context) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saving(ISaveContext context) throws CoreException {
|
||||||
|
context.needDelta();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* QNX Software Systems - Initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.qt.ui.text;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.qt.ui.QtUIPlugin;
|
||||||
|
import org.eclipse.cdt.internal.qt.ui.editor.QtProjectFileKeyword;
|
||||||
|
import org.eclipse.jface.text.BadLocationException;
|
||||||
|
import org.eclipse.jface.text.IDocument;
|
||||||
|
import org.eclipse.jface.text.ITextViewer;
|
||||||
|
import org.eclipse.jface.text.contentassist.CompletionProposal;
|
||||||
|
import org.eclipse.jface.text.contentassist.ICompletionProposal;
|
||||||
|
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
|
||||||
|
import org.eclipse.jface.text.contentassist.IContextInformation;
|
||||||
|
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
|
||||||
|
|
||||||
|
public class ContentAssistProcessor implements IContentAssistProcessor {
|
||||||
|
private final IContextInformation[] NO_CONTEXTS = {};
|
||||||
|
private final ICompletionProposal[] NO_COMPLETIONS = {};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
|
||||||
|
try {
|
||||||
|
IDocument document = viewer.getDocument();
|
||||||
|
ArrayList<ICompletionProposal> result = new ArrayList<>();
|
||||||
|
|
||||||
|
// Search the list of keywords (case-insensitive)
|
||||||
|
String prefix = lastWord(document, offset).toLowerCase(Locale.ROOT);
|
||||||
|
for (QtProjectFileKeyword keyword : QtProjectFileKeyword.values()) {
|
||||||
|
if (prefix.isEmpty() || keyword.getKeyword().toLowerCase(Locale.ROOT).startsWith(prefix)) {
|
||||||
|
result.add(new CompletionProposal(
|
||||||
|
keyword.getKeyword(),
|
||||||
|
offset - prefix.length(),
|
||||||
|
prefix.length(),
|
||||||
|
keyword.getKeyword().length()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toArray(new ICompletionProposal[result.size()]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
QtUIPlugin.log(e);
|
||||||
|
return NO_COMPLETIONS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the valid Java identifier in a document immediately before the given offset.
|
||||||
|
*
|
||||||
|
* @param document
|
||||||
|
* the document
|
||||||
|
* @param offset
|
||||||
|
* the offset at which to start looking
|
||||||
|
* @return the Java identifier preceding this location or a blank string if none
|
||||||
|
*/
|
||||||
|
private String lastWord(IDocument document, int offset) {
|
||||||
|
try {
|
||||||
|
for (int n = offset - 1; n >= 0; n--) {
|
||||||
|
char c = document.getChar(n);
|
||||||
|
if (!Character.isJavaIdentifierPart(c)) {
|
||||||
|
return document.get(n + 1, offset - n - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return document.get(0, offset);
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
QtUIPlugin.log(e);
|
||||||
|
}
|
||||||
|
return ""; //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
|
||||||
|
// No context information for now
|
||||||
|
return NO_CONTEXTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getErrorMessage() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IContextInformationValidator getContextInformationValidator() {
|
||||||
|
// No context information validator
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char[] getCompletionProposalAutoActivationCharacters() {
|
||||||
|
// No auto activation
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char[] getContextInformationAutoActivationCharacters() {
|
||||||
|
// No auto activation
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,9 @@ import org.eclipse.cdt.internal.qt.ui.editor.QtProjectFileKeyword;
|
||||||
import org.eclipse.jface.text.IDocument;
|
import org.eclipse.jface.text.IDocument;
|
||||||
import org.eclipse.jface.text.IDocumentExtension3;
|
import org.eclipse.jface.text.IDocumentExtension3;
|
||||||
import org.eclipse.jface.text.TextAttribute;
|
import org.eclipse.jface.text.TextAttribute;
|
||||||
|
import org.eclipse.jface.text.contentassist.ContentAssistant;
|
||||||
|
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
|
||||||
|
import org.eclipse.jface.text.contentassist.IContentAssistant;
|
||||||
import org.eclipse.jface.text.presentation.IPresentationReconciler;
|
import org.eclipse.jface.text.presentation.IPresentationReconciler;
|
||||||
import org.eclipse.jface.text.presentation.PresentationReconciler;
|
import org.eclipse.jface.text.presentation.PresentationReconciler;
|
||||||
import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
|
import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
|
||||||
|
@ -89,4 +92,12 @@ public class QtProjectFileSourceViewerConfiguration extends TextSourceViewerConf
|
||||||
return scanner;
|
return scanner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
|
||||||
|
ContentAssistant contentAssistant = new ContentAssistant();
|
||||||
|
IContentAssistProcessor processor = new ContentAssistProcessor();
|
||||||
|
contentAssistant.setContentAssistProcessor(processor, IDocument.DEFAULT_CONTENT_TYPE);
|
||||||
|
contentAssistant.setInformationControlCreator(getInformationControlCreator(sourceViewer));
|
||||||
|
return contentAssistant;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue