Merge pull request #6859 from bitrunner/cnd-meson-project
[CND] RFC: add meson build project support
diff --git a/cnd/cnd.kit/nbproject/project.xml b/cnd/cnd.kit/nbproject/project.xml
index cef5482..6de10dd 100644
--- a/cnd/cnd.kit/nbproject/project.xml
+++ b/cnd/cnd.kit/nbproject/project.xml
@@ -120,6 +120,12 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.modules.cnd.meson</code-name-base>
+ <run-dependency>
+ <specification-version>1.0</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.modules.cnd.remote</code-name-base>
<run-dependency>
<specification-version>1.0</specification-version>
diff --git a/cnd/cnd.meson/build.xml b/cnd/cnd.meson/build.xml
new file mode 100644
index 0000000..fddb9b7
--- /dev/null
+++ b/cnd/cnd.meson/build.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<project basedir="." default="netbeans" name="cnd/cnd.meson">
+ <description>Builds, tests, and runs the project org.netbeans.modules.cnd.meson</description>
+ <import file="../../nbbuild/templates/projectized.xml"/>
+</project>
diff --git a/cnd/cnd.meson/manifest.mf b/cnd/cnd.meson/manifest.mf
new file mode 100644
index 0000000..cb30e84
--- /dev/null
+++ b/cnd/cnd.meson/manifest.mf
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+AutoUpdate-Show-In-Client: false
+OpenIDE-Module: org.netbeans.modules.cnd.meson
+OpenIDE-Module-Layer: org/netbeans/modules/cnd/meson/resources/layer.xml
+OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/cnd/meson/editor/Bundle.properties
diff --git a/cnd/cnd.meson/nbproject/project.properties b/cnd/cnd.meson/nbproject/project.properties
new file mode 100644
index 0000000..e180d67
--- /dev/null
+++ b/cnd/cnd.meson/nbproject/project.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+javac.source=1.8
+javac.compilerargs=-Xlint -Xlint:-serial
+spec.version.base=1.0
diff --git a/cnd/cnd.meson/nbproject/project.xml b/cnd/cnd.meson/nbproject/project.xml
new file mode 100644
index 0000000..a6c7610
--- /dev/null
+++ b/cnd/cnd.meson/nbproject/project.xml
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<project xmlns="http://www.netbeans.org/ns/project/1">
+ <type>org.netbeans.modules.apisupport.project</type>
+ <configuration>
+ <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
+ <code-name-base>org.netbeans.modules.cnd.meson</code-name-base>
+ <module-dependencies>
+ <dependency>
+ <code-name-base>com.google.gson</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>2.8.9</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.api.templates</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>1.30</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.core.multiview</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>1</release-version>
+ <specification-version>1.66</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.cnd.api.project</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>1</release-version>
+ <implementation-version/>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.cnd.ui</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>1.4.1</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.editor</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>3</release-version>
+ <specification-version>1.109</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.editor.lib</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>3</release-version>
+ <specification-version>4.29</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.extexecution</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>2</release-version>
+ <specification-version>1.71</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.lexer</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>2</release-version>
+ <specification-version>1.85</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.projectapi</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>1</release-version>
+ <specification-version>1.93</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.projectuiapi</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>1</release-version>
+ <specification-version>1.111</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.projectuiapi.base</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>1</release-version>
+ <specification-version>1.108</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.openide.awt</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>7.90</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.openide.filesystems</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>9.35</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.openide.io</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>1.71</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.openide.loaders</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>7.92</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.openide.modules</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>7.70</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.openide.nodes</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>7.67</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.openide.text</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>6.90</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.openide.util</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>9.30</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.openide.util.lookup</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>8.56</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.openide.util.ui</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>9.31</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.openide.windows</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>6.99</specification-version>
+ </run-dependency>
+ </dependency>
+ </module-dependencies>
+ <public-packages/>
+ </data>
+ </configuration>
+</project>
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/Bundle.properties b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/Bundle.properties
new file mode 100644
index 0000000..99cd8ef
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/Bundle.properties
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+OpenIDE-Module-Display-Category=C/C++
+OpenIDE-Module-Long-Description=\
+ Supports C/C++ projects using the meson build system. \
+ The project typically is a native development project written in C or C++. \
+ However, since meson is not limited to these languages, this type of project can be used to build just about anything.
+OpenIDE-Module-Name=C/C++ Meson Build Project
+OpenIDE-Module-Short-Description=Supports C/C++ projects using the meson build system.
+Meson_NewProject=Meson
+Templates_meson=Meson Build Files
+
+comment=Comment
+error=Error
+identifier=Identifier
+keyword=Keyword
+number=Number
+operator=Operator
+string=String
+whitespace=Whitespace
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/MesonBuildKit.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/MesonBuildKit.java
new file mode 100644
index 0000000..9800a4b
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/MesonBuildKit.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.editor;
+
+import org.netbeans.modules.cnd.meson.editor.file.MIMETypes;
+
+public class MesonBuildKit extends MesonKit {
+ @Override
+ public String getContentType() {
+ return MIMETypes.MESON_BUILD;
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/MesonKit.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/MesonKit.java
new file mode 100644
index 0000000..5b37460
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/MesonKit.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.meson.editor;
+
+import javax.swing.Action;
+import javax.swing.text.Document;
+import javax.swing.text.TextAction;
+import org.netbeans.editor.BaseDocument;
+import org.netbeans.modules.editor.NbEditorKit;
+
+/**
+ * MesonKit is a meson tool specific extension of NbEditorKit that provides
+ * line commenting editor features.
+ */
+public abstract class MesonKit extends NbEditorKit {
+ private static final String COMMENT_LINE = "#"; //NOI18N
+
+ @Override
+ public Document createDefaultDocument() {
+ Document doc = super.createDefaultDocument();
+ doc.putProperty(BaseDocument.WRITE_LINE_SEPARATOR_PROP, BaseDocument.LS_LF);
+ return doc;
+ }
+
+ @Override
+ protected Action[] createActions() {
+ return
+ TextAction.augmentList(
+ super.createActions(),
+ new Action[] {
+ new CommentAction(COMMENT_LINE),
+ new UncommentAction(COMMENT_LINE),
+ new ToggleCommentAction(COMMENT_LINE)
+ }
+ );
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/MesonOptionsKit.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/MesonOptionsKit.java
new file mode 100644
index 0000000..f99a381
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/MesonOptionsKit.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.editor;
+
+import org.netbeans.modules.cnd.meson.editor.file.MIMETypes;
+
+public class MesonOptionsKit extends MesonKit {
+ @Override
+ public String getContentType() {
+ return MIMETypes.MESON_OPTIONS;
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/Bundle.properties b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/Bundle.properties
new file mode 100644
index 0000000..a327b58
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/Bundle.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+Source=&Source
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/MIMETypes.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/MIMETypes.java
new file mode 100644
index 0000000..c575d44
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/MIMETypes.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.editor.file;
+
+import org.openide.filesystems.MIMEResolver;
+import org.openide.util.NbBundle;
+
+@NbBundle.Messages({
+ "LBL_MESON_BUILD_MIME_RESOLVER=Meson MIME Resolver"
+})
+@MIMEResolver.Registration(
+ displayName = "#LBL_MESON_BUILD_MIME_RESOLVER",
+ position = 139, // anything > 140 causes meson_options.txt to not be recognized
+ resource = "../../resources/mime_resolver.xml"
+)
+public class MIMETypes {
+ public static final String MESON_BUILD = "text/x-meson-build"; //NOI18N
+ public static final String MESON_OPTIONS = "text/x-meson-options"; //NOI18N
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/MesonBuildDataObject.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/MesonBuildDataObject.java
new file mode 100644
index 0000000..d93aef6
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/MesonBuildDataObject.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.editor.file;
+
+import java.io.IOException;
+
+import org.netbeans.core.spi.multiview.MultiViewElement;
+import org.netbeans.core.spi.multiview.text.MultiViewEditorElement;
+import org.openide.awt.ActionID;
+import org.openide.awt.ActionReference;
+import org.openide.awt.ActionReferences;
+import org.openide.filesystems.FileObject;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.MultiDataObject;
+import org.openide.loaders.MultiFileLoader;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle.Messages;
+import org.openide.windows.TopComponent;
+
+@Messages({
+ "LBL_MESON_BUILD_LOADER=meson.build file loader"
+})
+@DataObject.Registration(
+ mimeType = MIMETypes.MESON_BUILD,
+ iconBase = MesonBuildDataObject.ICON,
+ displayName = "#LBL_MESON_BUILD_LOADER",
+ position = 500
+)
+@ActionReferences({
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_BUILD + "/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.OpenAction"),
+ position = 100,
+ separatorAfter = 200
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_BUILD + "/Actions",
+ id = @ActionID(category = "Edit", id = "org.openide.actions.CutAction"),
+ position = 300
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_BUILD + "/Actions",
+ id = @ActionID(category = "Edit", id = "org.openide.actions.CopyAction"),
+ position = 400,
+ separatorAfter = 500
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_BUILD + "/Actions",
+ id = @ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"),
+ position = 600
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_BUILD + "/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.RenameAction"),
+ position = 700,
+ separatorAfter = 800
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_BUILD + "/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"),
+ position = 900,
+ separatorAfter = 1000
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_BUILD + "/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.FileSystemAction"),
+ position = 1100,
+ separatorAfter = 1200
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_BUILD + "/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.ToolsAction"),
+ position = 1300
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_BUILD + "/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.PropertiesAction"),
+ position = 1400
+ ),
+ @ActionReference(
+ path = "Editors/" + MIMETypes.MESON_BUILD + "/Popup",
+ id = @ActionID(category = "Refactoring", id = "org.netbeans.modules.refactoring.api.ui.WhereUsedAction"),
+ position = 1400
+ ),
+ @ActionReference(
+ path = "Editors/" + MIMETypes.MESON_BUILD + "/Popup",
+ id = @ActionID(category = "Refactoring", id = "org.netbeans.modules.refactoring.api.ui.RenameAction"),
+ position = 1500,
+ separatorAfter = 1550
+ )
+})
+public class MesonBuildDataObject extends MultiDataObject {
+ public static final String ICON = "org/netbeans/modules/cnd/meson/resources/file_icon.png";
+ @SuppressWarnings("this-escape")
+ public MesonBuildDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException {
+ super(pf, loader);
+ registerEditor(MIMETypes.MESON_BUILD, true);
+ }
+
+ @MultiViewElement.Registration(
+ displayName = "#Source",
+ iconBase = MesonBuildDataObject.ICON, //NOI18N
+ persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED,
+ mimeType = MIMETypes.MESON_BUILD,
+ preferredID = "meson.build.file.source", //NOI18N
+ position = 1)
+ public static MultiViewEditorElement createMultiViewEditorElement(Lookup context) {
+ return new MultiViewEditorElement(context);
+ }
+
+ @Override
+ protected int associateLookup() {
+ return 1;
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/MesonOptionsDataObject.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/MesonOptionsDataObject.java
new file mode 100644
index 0000000..3da9c61
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/MesonOptionsDataObject.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.editor.file;
+
+import java.io.IOException;
+
+import org.netbeans.core.spi.multiview.MultiViewElement;
+import org.netbeans.core.spi.multiview.text.MultiViewEditorElement;
+import org.openide.awt.ActionID;
+import org.openide.awt.ActionReference;
+import org.openide.awt.ActionReferences;
+import org.openide.filesystems.FileObject;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.MultiDataObject;
+import org.openide.loaders.MultiFileLoader;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle.Messages;
+import org.openide.windows.TopComponent;
+
+@Messages({
+ "LBL_MESON_OPTIONS_LOADER=meson.options file loader"
+})
+@DataObject.Registration(
+ mimeType = MIMETypes.MESON_OPTIONS,
+ iconBase = MesonOptionsDataObject.ICON,
+ displayName = "#LBL_MESON_OPTIONS_LOADER",
+ position = 501
+)
+@ActionReferences({
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_OPTIONS + "/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.OpenAction"),
+ position = 100,
+ separatorAfter = 200
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_OPTIONS + "/Actions",
+ id = @ActionID(category = "Edit", id = "org.openide.actions.CutAction"),
+ position = 300
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_OPTIONS + "/Actions",
+ id = @ActionID(category = "Edit", id = "org.openide.actions.CopyAction"),
+ position = 400,
+ separatorAfter = 500
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_OPTIONS + "/Actions",
+ id = @ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"),
+ position = 600
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_OPTIONS + "/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.RenameAction"),
+ position = 700,
+ separatorAfter = 800
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_OPTIONS + "/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"),
+ position = 900,
+ separatorAfter = 1000
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_OPTIONS + "/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.FileSystemAction"),
+ position = 1100,
+ separatorAfter = 1200
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_OPTIONS + "/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.ToolsAction"),
+ position = 1300
+ ),
+ @ActionReference(
+ path = "Loaders/" + MIMETypes.MESON_OPTIONS + "/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.PropertiesAction"),
+ position = 1400
+ ),
+ @ActionReference(
+ path = "Editors/" + MIMETypes.MESON_OPTIONS + "/Popup",
+ id = @ActionID(category = "Refactoring", id = "org.netbeans.modules.refactoring.api.ui.WhereUsedAction"),
+ position = 1400
+ ),
+ @ActionReference(
+ path = "Editors/" + MIMETypes.MESON_OPTIONS + "/Popup",
+ id = @ActionID(category = "Refactoring", id = "org.netbeans.modules.refactoring.api.ui.RenameAction"),
+ position = 1500,
+ separatorAfter = 1550
+ )
+})
+public class MesonOptionsDataObject extends MultiDataObject {
+ public static final String ICON = "org/netbeans/modules/cnd/meson/resources/file_icon.png";
+ @SuppressWarnings("this-escape")
+ public MesonOptionsDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException {
+ super(pf, loader);
+ registerEditor(MIMETypes.MESON_OPTIONS, true);
+ }
+
+ @MultiViewElement.Registration(
+ displayName = "#Source",
+ iconBase = MesonOptionsDataObject.ICON, //NOI18N
+ persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED,
+ mimeType = MIMETypes.MESON_OPTIONS,
+ preferredID = "meson.options.file.source", //NOI18N
+ position = 1)
+ public static MultiViewEditorElement createMultiViewEditorElement(Lookup context) {
+ return new MultiViewEditorElement(context);
+ }
+
+ @Override
+ protected int associateLookup() {
+ return 1;
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/package-info.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/package-info.java
new file mode 100644
index 0000000..c15cf62
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/editor/file/package-info.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+@TemplateRegistrations({
+ @TemplateRegistration(folder = "meson",
+ targetName = "meson",
+ content = "../../resources/meson.build.template",
+ scriptEngine = "freemarker",
+ category = "meson-types",
+ displayName = "meson.build",
+ iconBase = MesonBuildDataObject.ICON),
+ @TemplateRegistration(folder = "meson",
+ targetName = "meson",
+ content = "../../resources/meson.options.template",
+ scriptEngine="freemarker",
+ category = "meson-types",
+ displayName = "meson.options",
+ iconBase = MesonOptionsDataObject.ICON),
+})
+package org.netbeans.modules.cnd.meson.editor.file;
+
+import org.netbeans.api.templates.TemplateRegistration;
+import org.netbeans.api.templates.TemplateRegistrations;
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonBuildLanguageHierarchy.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonBuildLanguageHierarchy.java
new file mode 100644
index 0000000..e2b536c
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonBuildLanguageHierarchy.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.meson.lexer;
+
+import java.util.Collection;
+import java.util.EnumSet;
+import org.netbeans.spi.lexer.LanguageHierarchy;
+import org.netbeans.spi.lexer.Lexer;
+import org.netbeans.spi.lexer.LexerRestartInfo;
+
+/**
+ *
+ */
+public class MesonBuildLanguageHierarchy extends LanguageHierarchy<MesonBuildTokenId> {
+ private final String mime;
+
+ public MesonBuildLanguageHierarchy(String mime) {
+ this.mime = mime;
+ }
+
+ @Override
+ protected synchronized Collection<MesonBuildTokenId> createTokenIds() {
+ return EnumSet.allOf(MesonBuildTokenId.class);
+ }
+
+ @Override
+ protected Lexer<MesonBuildTokenId> createLexer(LexerRestartInfo<MesonBuildTokenId> info) {
+ return new MesonBuildLexer(info);
+ }
+
+ @Override
+ protected String mimeType() {
+ return mime;
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonBuildLexer.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonBuildLexer.java
new file mode 100644
index 0000000..136a67c
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonBuildLexer.java
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.meson.lexer;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.netbeans.api.lexer.Token;
+import org.netbeans.spi.lexer.Lexer;
+import org.netbeans.spi.lexer.LexerInput;
+import org.netbeans.spi.lexer.LexerRestartInfo;
+
+/**
+ *
+ */
+public class MesonBuildLexer implements Lexer<MesonBuildTokenId> {
+ private static final Set<String> functions = new HashSet<>();
+ private static final Set<String> objects = new HashSet<>();
+ private static final Set<String> keywords = new HashSet<>();
+ private static final Set<String> literals = new HashSet<>();
+
+ static {
+ functions.add("add_global_arguments"); // NOI18N
+ functions.add("add_global_link_arguments"); // NOI18N
+ functions.add("add_languages"); // NOI18N
+ functions.add("add_project_arguments"); // NOI18N
+ functions.add("add_project_dependencies"); // NOI18N
+ functions.add("add_project_link_arguments"); // NOI18N
+ functions.add("add_test_setup"); // NOI18N
+ functions.add("alias_target"); // NOI18N
+ functions.add("assert"); // NOI18N
+ functions.add("benchmark"); // NOI18N
+ functions.add("both_libraries"); // NOI18N
+ functions.add("build_target"); // NOI18N
+ functions.add("configuration_data"); // NOI18N
+ functions.add("configure_file"); // NOI18N
+ functions.add("custom_target"); // NOI18N
+ functions.add("debug"); // NOI18N
+ functions.add("declare_dependency"); // NOI18N
+ functions.add("dependency"); // NOI18N
+ functions.add("disabler"); // NOI18N
+ functions.add("environment"); // NOI18N
+ functions.add("error"); // NOI18N
+ functions.add("executable"); // NOI18N
+ functions.add("files"); // NOI18N
+ functions.add("find_program"); // NOI18N
+ functions.add("generator"); // NOI18N
+ functions.add("get_option"); // NOI18N
+ functions.add("get_variable"); // NOI18N
+ functions.add("import"); // NOI18N
+ functions.add("include_directories"); // NOI18N
+ functions.add("install_data"); // NOI18N
+ functions.add("install_emptydir"); // NOI18N
+ functions.add("install_headers"); // NOI18N
+ functions.add("install_man"); // NOI18N
+ functions.add("install_subdir"); // NOI18N
+ functions.add("install_symlink"); // NOI18N
+ functions.add("is_disabler"); // NOI18N
+ functions.add("is_variable"); // NOI18N
+ functions.add("jar"); // NOI18N
+ functions.add("join_paths"); // NOI18N
+ functions.add("library"); // NOI18N
+ functions.add("message"); // NOI18N
+ functions.add("project"); // NOI18N
+ functions.add("range"); // NOI18N
+ functions.add("run_command"); // NOI18N
+ functions.add("run_target"); // NOI18N
+ functions.add("set_variable"); // NOI18N
+ functions.add("shared_library"); // NOI18N
+ functions.add("shared_module"); // NOI18N
+ functions.add("static_library"); // NOI18N
+ functions.add("structured_sources"); // NOI18N
+ functions.add("subdir"); // NOI18N
+ functions.add("subdir_done"); // NOI18N
+ functions.add("subproject"); // NOI18N
+ functions.add("summary"); // NOI18N
+ functions.add("test"); // NOI18N
+ functions.add("unset_variable"); // NOI18N
+ functions.add("vcs_tag"); // NOI18N
+ functions.add("warning"); // NOI18N
+
+ objects.add("build_machine"); // NOI18N
+ objects.add("host_machine"); // NOI18N
+ objects.add("meson"); // NOI18N
+ objects.add("target_machine"); // NOI18N
+
+ keywords.add("and"); // NOI18N
+ keywords.add("break"); // NOI18N
+ keywords.add("continue"); // NOI18N
+ keywords.add("elif"); // NOI18N
+ keywords.add("else"); // NOI18N
+ keywords.add("endforeach"); // NOI18N
+ keywords.add("endif"); // NOI18N
+ keywords.add("foreach"); // NOI18N
+ keywords.add("if"); // NOI18N
+ keywords.add("not"); // NOI18N
+ keywords.add("or"); // NOI18N
+
+ literals.add("false"); // NOI18N
+ literals.add("true"); // NOI18N
+ }
+
+ private final LexerRestartInfo<MesonBuildTokenId> info;
+
+ MesonBuildLexer(LexerRestartInfo<MesonBuildTokenId> info) {
+ this.info = info;
+ }
+
+ @Override
+ public Token<MesonBuildTokenId> nextToken () {
+ LexerInput input = info.input ();
+ int i = input.read ();
+ switch (i) {
+ case LexerInput.EOF:
+ return null;
+ case '+':
+ case '<':
+ case '>':
+ case '!':
+ case '=':
+ case ',':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ case '-':
+ case '*':
+ case '/':
+ case '\\':
+ case ':':
+ case '?':
+ case '.':
+ case '%':
+ return info.tokenFactory().createToken(MesonBuildTokenId.OPERATOR);
+ case ' ':
+ case '\n':
+ case '\r':
+ case '\t':
+ do {
+ i = input.read();
+ } while ((i == ' ') || (i == '\n') || (i == '\r') || (i == '\t'));
+ if (i != LexerInput.EOF) {
+ input.backup(1);
+ }
+ return info.tokenFactory().createToken(MesonBuildTokenId.WHITESPACE);
+ case '#':
+ do {
+ i = input.read();
+ } while ((i != '\n') && (i != '\r') && (i != LexerInput.EOF));
+ return info.tokenFactory().createToken(MesonBuildTokenId.COMMENT);
+ case '\'':
+ // meson supports simple string literals like 'string'
+ // and multiline string literals like '''some really
+ // long string'''
+ if (input.read() == '\'') {
+ if (input.read() == '\'') {
+ do {
+ i = input.read();
+ if (i == '\'') {
+ i = input.read();
+ if (i == '\'') {
+ i = input.read();
+ if (i == '\'') {
+ break;
+ } else {
+ input.backup(2);
+ }
+ } else {
+ input.backup(1);
+ }
+ }
+ } while (i != LexerInput.EOF);
+ return info.tokenFactory().createToken(MesonBuildTokenId.STRING);
+ } else {
+ input.backup(2);
+ }
+ } else {
+ input.backup(1);
+ }
+ do {
+ i = input.read();
+ if (i == '\\') { // string literals can contain escape sequences
+ input.read();
+ i = input.read();
+ }
+ } while ((i != '\'') && (i != '\n') && (i != '\r') && (i != LexerInput.EOF));
+ return info.tokenFactory().createToken(MesonBuildTokenId.STRING);
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ // meson only supports integer numeric literals
+ // hexadecimal literals are supported starting with 0x
+ // octal literals are supported starting with 0o
+ // binary literals are supported starting with 0b
+ if (i == '0') {
+ i = input.read();
+ switch (i) {
+ case 'x':
+ do {
+ i = java.lang.Character.toLowerCase(input.read());
+ } while ( ((i >= '0') && (i <= '9'))
+ || ((i >= 'a') && (i <= 'f')));
+ input.backup(1);
+ return info.tokenFactory().createToken(MesonBuildTokenId.NUMBER);
+ case 'o':
+ do {
+ i = input.read();
+ } while ((i >= '0') && (i <= '7'));
+ input.backup(1);
+ return info.tokenFactory().createToken(MesonBuildTokenId.NUMBER);
+ case 'b':
+ do {
+ i = input.read();
+ } while ((i == '0') || (i == '1'));
+ input.backup(1);
+ return info.tokenFactory().createToken(MesonBuildTokenId.NUMBER);
+ }
+ }
+ do {
+ i = input.read();
+ } while ((i >= '0') && (i <= '9'));
+ input.backup(1);
+ return info.tokenFactory().createToken(MesonBuildTokenId.NUMBER);
+ default:
+ if ( (i >= 'a' && i <= 'z')
+ || (i >= 'A' && i <= 'Z')
+ || (i == '_')) {
+ do {
+ i = input.read();
+ } while ( ((i >= 'a') && (i <= 'z'))
+ || ((i >= 'A') && (i <= 'Z'))
+ || ((i >= '0') && (i <= '9'))
+ || (i == '_'));
+ input.backup(1);
+ final String token = input.readText().toString();
+ if (keywords.contains(token)) {
+ return info.tokenFactory().createToken(MesonBuildTokenId.KEYWORD);
+ }
+ else if (functions.contains(token)) {
+ return info.tokenFactory().createToken(MesonBuildTokenId.FUNCTION);
+ }
+ else if (objects.contains(token)) {
+ return info.tokenFactory().createToken(MesonBuildTokenId.OBJECT);
+ }
+ else if (literals.contains(token)) {
+ return info.tokenFactory().createToken(MesonBuildTokenId.LITERAL);
+ }
+ return info.tokenFactory().createToken(MesonBuildTokenId.IDENTIFIER);
+ }
+ return info.tokenFactory().createToken(MesonBuildTokenId.ERROR);
+ }
+ }
+
+ @Override
+ public Object state() {
+ return null;
+ }
+
+ @Override
+ public void release() {
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonBuildTokenId.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonBuildTokenId.java
new file mode 100644
index 0000000..e9dd105
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonBuildTokenId.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.meson.lexer;
+
+import org.netbeans.api.lexer.Language;
+import org.netbeans.api.lexer.TokenId;
+import org.netbeans.modules.cnd.meson.editor.file.MIMETypes;
+
+/**
+ * Meson build script tokens.
+ */
+public enum MesonBuildTokenId implements TokenId {
+ /**
+ * Space, tab, newline, etc. that does not have any special meaning.
+ */
+ WHITESPACE("whitespace"), // NOI18N
+
+ /**
+ * Comment: starts with <code>#</code> and ends at line end.
+ */
+ COMMENT("comment"), // NOI18N
+
+ /**
+ * Meson builtin functions.
+ */
+ FUNCTION("keyword"), // NOI18N
+
+ /**
+ * Meson builtin objects.
+ */
+ OBJECT("keyword"), // NOI18N
+
+ /**
+ * Meson keywords.
+ */
+ KEYWORD("keyword"), // NOI18N
+
+ /**
+ * Meson string literals.
+ */
+ STRING("string"), // NOI18N
+
+ /**
+ * Meson literals (boolean true and false).
+ */
+ LITERAL("literal"), // NOI18N
+
+ /**
+ * Meson number literals.
+ */
+ NUMBER("number"), // NOI18N
+
+ /**
+ * Meson operators.
+ */
+ OPERATOR("operator"), // NOI18N
+
+ /**
+ * Meson identifiers (variable names, etc.)
+ */
+ IDENTIFIER("identifier"), // NOI18N
+
+ /**
+ * This token is returned when something goes wrong while evaluating the source file.
+ */
+ ERROR("error"); // NOI18N
+
+ private final String category;
+
+ private MesonBuildTokenId(String category) {
+ this.category = category;
+ }
+
+ @Override
+ public String primaryCategory() {
+ return category;
+ }
+
+ private static final Language<MesonBuildTokenId> LANGUAGE =
+ new MesonBuildLanguageHierarchy(MIMETypes.MESON_BUILD).language();
+
+ public static Language<MesonBuildTokenId> language() {
+ return LANGUAGE;
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonOptionsLanguageHierarchy.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonOptionsLanguageHierarchy.java
new file mode 100644
index 0000000..28feea1
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonOptionsLanguageHierarchy.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.lexer;
+
+import java.util.Collection;
+import java.util.EnumSet;
+import org.netbeans.spi.lexer.LanguageHierarchy;
+import org.netbeans.spi.lexer.Lexer;
+import org.netbeans.spi.lexer.LexerRestartInfo;
+
+/**
+ *
+ */
+public class MesonOptionsLanguageHierarchy extends LanguageHierarchy<MesonOptionsTokenId> {
+ private final String mime;
+
+ public MesonOptionsLanguageHierarchy(String mime) {
+ this.mime = mime;
+ }
+
+ @Override
+ protected synchronized Collection<MesonOptionsTokenId> createTokenIds() {
+ return EnumSet.allOf(MesonOptionsTokenId.class);
+ }
+
+ @Override
+ protected Lexer<MesonOptionsTokenId> createLexer(LexerRestartInfo<MesonOptionsTokenId> info) {
+ return new MesonOptionsLexer(info);
+ }
+
+ @Override
+ protected String mimeType() {
+ return mime;
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonOptionsLexer.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonOptionsLexer.java
new file mode 100644
index 0000000..cc777ff
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonOptionsLexer.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.lexer;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.netbeans.api.lexer.Token;
+import org.netbeans.spi.lexer.Lexer;
+import org.netbeans.spi.lexer.LexerInput;
+import org.netbeans.spi.lexer.LexerRestartInfo;
+
+public class MesonOptionsLexer implements Lexer<MesonOptionsTokenId> {
+ private static final Set<String> keywords = new HashSet<>();
+ private static final Set<String> literals = new HashSet<>();
+
+ static {
+ keywords.add("choices"); // NOI18N
+ keywords.add("deprecated"); // NOI18N
+ keywords.add("description"); // NOI18N
+ keywords.add("max"); // NOI18N
+ keywords.add("min"); // NOI18N
+ keywords.add("type"); // NOI18N
+ keywords.add("value"); // NOI18N
+ keywords.add("yield"); // NOI18N
+
+ literals.add("false"); // NOI18N
+ literals.add("true"); // NOI18N
+ }
+
+ private final LexerRestartInfo<MesonOptionsTokenId> info;
+
+ MesonOptionsLexer(LexerRestartInfo<MesonOptionsTokenId> info) {
+ this.info = info;
+ }
+
+ @Override
+ public Token<MesonOptionsTokenId> nextToken () {
+ LexerInput input = info.input ();
+ int i = input.read ();
+ switch (i) {
+ case LexerInput.EOF:
+ return null;
+ case '+':
+ case ',':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ case ':':
+ return info.tokenFactory().createToken(MesonOptionsTokenId.OPERATOR);
+ case ' ':
+ case '\n':
+ case '\r':
+ case '\t':
+ do {
+ i = input.read();
+ } while ((i == ' ') || (i == '\n') || (i == '\r') || (i == '\t'));
+ if (i != LexerInput.EOF) {
+ input.backup(1);
+ }
+ return info.tokenFactory().createToken(MesonOptionsTokenId.WHITESPACE);
+ case '#':
+ do {
+ i = input.read();
+ } while ((i != '\n') && (i != '\r') && (i != LexerInput.EOF));
+ return info.tokenFactory().createToken(MesonOptionsTokenId.COMMENT);
+ case '\'':
+ // meson options files only support simple string literals like 'string'
+ do {
+ i = input.read();
+ } while ((i != '\'') && (i != '\n') && (i != '\r') && (i != LexerInput.EOF));
+ return info.tokenFactory().createToken(MesonOptionsTokenId.STRING);
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ // meson options files only support integer numeric literals
+ do {
+ i = input.read();
+ } while ((i >= '0') && (i <= '9'));
+ input.backup(1);
+ return info.tokenFactory().createToken(MesonOptionsTokenId.NUMBER);
+ default:
+ if ( (i >= 'a' && i <= 'z')
+ || (i >= 'A' && i <= 'Z')) {
+ do {
+ i = input.read();
+ } while ( ((i >= 'a') && (i <= 'z'))
+ || ((i >= 'A') && (i <= 'Z')));
+ input.backup(1);
+ final String token = input.readText().toString();
+ if ("option".equals(token)) {
+ return info.tokenFactory().createToken(MesonOptionsTokenId.OPTION);
+ }
+ else if (keywords.contains(token)) {
+ return info.tokenFactory().createToken(MesonOptionsTokenId.ARGUMENT_KEYWORD);
+ }
+ else if (literals.contains(token)) {
+ return info.tokenFactory().createToken(MesonOptionsTokenId.LITERAL);
+ }
+ }
+ return info.tokenFactory().createToken(MesonOptionsTokenId.ERROR);
+ }
+ }
+
+ @Override
+ public Object state() {
+ return null;
+ }
+
+ @Override
+ public void release() {
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonOptionsTokenId.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonOptionsTokenId.java
new file mode 100644
index 0000000..320cfc6
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/lexer/MesonOptionsTokenId.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.meson.lexer;
+
+import org.netbeans.api.lexer.Language;
+import org.netbeans.api.lexer.TokenId;
+import org.netbeans.modules.cnd.meson.editor.file.MIMETypes;
+
+/**
+ * Meson options file tokens.
+ */
+public enum MesonOptionsTokenId implements TokenId {
+ /**
+ * Space, tab, newline, etc. that does not have any special meaning.
+ */
+ WHITESPACE("whitespace"), // NOI18N
+
+ /**
+ * Comment: starts with <code>#</code> and ends at line end.
+ */
+ COMMENT("comment"), // NOI18N
+
+ /**
+ * Meson option keyword.
+ */
+ OPTION("keyword"), // NOI18N
+
+ /**
+ * Meson option literals (boolean true and false).
+ */
+ LITERAL("literal"), // NOI18N
+
+ /**
+ * Meson option string literals.
+ */
+ STRING("string"), // NOI18N
+
+ /**
+ * Meson option number literals.
+ */
+ NUMBER("number"), // NOI18N
+
+ /**
+ * Meson option operators.
+ */
+ OPERATOR("operator"), // NOI18N
+
+ /**
+ * Meson option argument keywords.
+ */
+ ARGUMENT_KEYWORD("keyword"), // NOI18N
+
+ /**
+ * This token is returned when something goes wrong while evaluating the source file.
+ */
+ ERROR("error"); // NOI18N
+
+ private final String category;
+
+ private MesonOptionsTokenId(String category) {
+ this.category = category;
+ }
+
+ @Override
+ public String primaryCategory() {
+ return category;
+ }
+
+ private static final Language<MesonOptionsTokenId> LANGUAGE =
+ new MesonOptionsLanguageHierarchy(MIMETypes.MESON_OPTIONS).language();
+
+ public static Language<MesonOptionsTokenId> language() {
+ return LANGUAGE;
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ActionProviderImpl.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ActionProviderImpl.java
new file mode 100644
index 0000000..4695cfb
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ActionProviderImpl.java
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.meson.project;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.swing.Action;
+import org.netbeans.api.extexecution.ExecutionDescriptor;
+import org.netbeans.api.extexecution.ExecutionService;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.spi.project.ActionProvider;
+import org.netbeans.spi.project.ui.support.ProjectSensitiveActions;
+import org.openide.LifecycleManager;
+import org.openide.filesystems.FileUtil;
+import org.openide.modules.InstalledFileLocator;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle;
+
+public class ActionProviderImpl implements ActionProvider {
+ public static final String COMMAND_SETUP = "setup"; // NOI18N
+ public static final String COMMAND_DEBUG_TEST = "debug.test"; // NOI18N
+ public static final String COMMAND_DEBUG_STEP_INTO_TEST = "debug.stepinto.test"; // NOI18N
+
+ private static final String[] SUPPORTED_ACTIONS = {
+ COMMAND_SETUP,
+ COMMAND_BUILD,
+ COMMAND_CLEAN,
+ COMMAND_REBUILD,
+ COMMAND_RUN,
+ COMMAND_DEBUG,
+ COMMAND_DEBUG_STEP_INTO,
+ COMMAND_DEBUG_SINGLE,
+ COMMAND_TEST,
+ COMMAND_DEBUG_TEST,
+ COMMAND_DEBUG_STEP_INTO_TEST,
+ };
+
+ private final MesonProject project;
+
+ public ActionProviderImpl(MesonProject project) {
+ this.project = project;
+ }
+
+ @Override
+ @SuppressWarnings("ReturnOfCollectionOrArrayField")
+ public String[] getSupportedActions() {
+ return SUPPORTED_ACTIONS;
+ }
+
+ @Override
+ public void invokeAction(String action, Lookup context) throws IllegalArgumentException {
+ File module = InstalledFileLocator.getDefault().locate("modules/org-netbeans-modules-cnd-meson.jar", "org.netbeans.modules.cnd.meson", false);
+
+ ExecutionDescriptor executionDescriptor =
+ new ExecutionDescriptor()
+ .showProgress(true)
+ .showSuspended(true)
+ .frontWindowOnError(true)
+ .controllable(true)
+ .errConvertorFactory(new LineConvertorFactoryImpl())
+ .outConvertorFactory(new LineConvertorFactoryImpl())
+ .postExecution(
+ () -> {
+ FileUtil.refreshFor(Paths.get(project.getProjectDirectory().getPath(), project.getActiveConfiguration().getBuildDirectory(), MesonProject.INFO_DIRECTORY).toFile());
+ });
+
+ ExecutionService.newService(
+ () -> {
+ LifecycleManager.getDefault().saveAll();
+
+ List<List<String>> commandsToExecute = new ArrayList<>();
+ Configuration cfg = project.getActiveConfiguration();
+ File runDir = FileUtil.toFile(project.getProjectDirectory());
+ File buildDir = Paths.get(project.getProjectDirectory().getPath(), cfg.getBuildDirectory()).toFile();
+
+ if (!buildDirectoryIsValid(buildDir) && !action.equals(COMMAND_SETUP)) {
+ commandsToExecute.add(getMesonCommandLineFor(COMMAND_SETUP));
+ }
+
+ switch (action)
+ {
+ case COMMAND_REBUILD:
+ if (buildDir.exists()) {
+ commandsToExecute.add(getMesonCommandLineFor(COMMAND_CLEAN));
+ }
+ commandsToExecute.add(getMesonCommandLineFor(COMMAND_BUILD));
+ break;
+ case COMMAND_RUN:
+ if (!buildDir.exists()) {
+ commandsToExecute.add(getMesonCommandLineFor(COMMAND_BUILD));
+ }
+ commandsToExecute.add(Arrays.asList(cfg.getRunExecutable(), cfg.getRunArguments()));
+ if ((cfg.getRunDirectory() != null) && !cfg.getRunDirectory().isEmpty()) {
+ runDir = Paths.get(project.getProjectDirectory().getPath(), cfg.getRunDirectory()).toFile();
+ }
+ break;
+ case COMMAND_DEBUG:
+ // TODO
+ break;
+ default:
+ List<String> command = getMesonCommandLineFor(action);
+ if (command != null) {
+ commandsToExecute.add(command);
+ } break;
+ }
+ String arg = Utils.encode(commandsToExecute);
+ return new ProcessBuilder("java", "-classpath", module.getAbsolutePath(), Runner.class.getName(), arg).directory(runDir).start();
+ },
+ executionDescriptor,
+ ProjectUtils.getInformation(project).getDisplayName() + " - " + action
+ ).run();
+ }
+
+ @Override
+ public boolean isActionEnabled(String command, Lookup context) throws IllegalArgumentException {
+ if (null != command) switch (command)
+ {
+ case COMMAND_DEBUG:
+ return false; //isActionEnabled(COMMAND_RUN, context);
+ case COMMAND_REBUILD:
+ return isActionEnabled(COMMAND_CLEAN, context) && isActionEnabled(COMMAND_BUILD, context);
+ case COMMAND_RUN:
+ Configuration cfg = project.getActiveConfiguration();
+ return !Utils.isEmpty(cfg.getRunExecutable()) && Paths.get(project.getProjectDirectory().getPath(), cfg.getRunExecutable()).toFile().isFile();
+ default:
+ break;
+ }
+ return true;
+ }
+
+ private List<String> getMesonCommandLineFor(String action) {
+ List<String> command = null;
+ Configuration config = project.getActiveConfiguration();
+
+ switch (action) {
+ case COMMAND_BUILD:
+ command = new ArrayList<>();
+ command.add("meson"); //NOI18N
+ command.add("compile"); //NOI18N
+ command.add("-C"); //NOI18N
+ command.add(config.getBuildDirectory());
+ command.add(config.getAdditionalArgumentsFor(action));
+ break;
+
+ case COMMAND_CLEAN:
+ command = new ArrayList<>();
+ command.add("meson"); //NOI18N
+ command.add("compile"); //NOI18N
+ command.add("-C"); //NOI18N
+ command.add(config.getBuildDirectory());
+ command.add("--clean"); //NOI18N
+ break;
+
+ case COMMAND_SETUP:
+ command = new ArrayList<>();
+ command.add("meson"); //NOI18N
+ command.add("setup"); //NOI18N
+ command.add("--wipe"); //NOI18N
+
+ if (!Utils.isEmpty(config.getBuildType())) {
+ command.add("--buildtype"); //NOI18N
+ command.add(config.getBuildType());
+ }
+
+ if (!Utils.isEmpty(config.getWrapMode())) {
+ command.add("--wrap-mode"); //NOI18N
+ command.add(config.getWrapMode());
+ }
+
+ command.add(config.getAdditionalArgumentsFor(action));
+ command.add(config.getBuildDirectory());
+ break;
+
+ case COMMAND_TEST:
+ command = new ArrayList<>();
+ command.add("meson"); //NOI18N
+ command.add("test"); //NOI18N
+ command.add("-C"); //NOI18N
+ command.add(config.getBuildDirectory());
+ command.add(config.getAdditionalArgumentsFor(action));
+ break;
+ }
+
+ return command;
+ }
+
+ public static final class Runner {
+ /**
+ * @param args the command line arguments
+ */
+ public static void main(String[] args) throws Exception {
+ for (List<String> command : Utils.decode(args[0])) {
+ int result = new ProcessBuilder(command).inheritIO().start().waitFor();
+ if (result != 0) {
+ System.exit(result);
+ }
+ }
+ }
+ }
+
+ public static Action createSetupAction() {
+ return
+ ProjectSensitiveActions.projectCommandAction(
+ COMMAND_SETUP,
+ NbBundle.getMessage(ActionProviderImpl.class, "LBL_MesonSetupCommand"),
+ MesonProject.getIcon());
+ }
+
+ private static final class MesonInfo {
+ boolean error;
+ };
+
+ private static boolean buildDirectoryIsValid(File buildDirectory) {
+ if (buildDirectory.exists()) {
+ try {
+ MesonInfo info = new Gson().fromJson(new FileReader(Paths.get(buildDirectory.toString(), MesonProject.MESON_INFO_JSON).toFile()), new TypeToken<MesonInfo>(){}.getType());
+ return (info != null) && !info.error;
+ }
+ catch (FileNotFoundException ignored) {
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/Bundle.properties b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/Bundle.properties
new file mode 100644
index 0000000..cf4d59f
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/Bundle.properties
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+OpenIDE-Module-Display-Category=C/C++
+OpenIDE-Module-Name=C/C++ Meson Projects
+OpenIDE-Module-Short-Description=Support for Meson Build Based Projects
+LBL_MesonSetupCommand=Setup
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/Configuration.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/Configuration.java
new file mode 100644
index 0000000..602e741
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/Configuration.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.project;
+
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.netbeans.spi.project.ProjectConfiguration;
+
+public class Configuration implements ProjectConfiguration
+{
+ private Map<String, String> additionalArguments;
+ private String buildDirectory;
+ private String buildType;
+ private String backend;
+ private String name;
+ private String runArguments;
+ private String runDirectory;
+ private String runExecutable;
+ private String wrapMode;
+
+ public Configuration(
+ String name, String buildDirectory, String buildType, String backend,
+ String wrapMode, String runDirectory, String runExecutable, String runArguments,
+ Map<String, String> additionalArguments) {
+ this.name = name;
+ this.buildDirectory = buildDirectory;
+ this.buildType = buildType;
+ this.backend = backend;
+ this.runArguments = runArguments;
+ this.runDirectory = runDirectory;
+ this.runExecutable = runExecutable;
+ this.wrapMode = wrapMode;
+ this.additionalArguments = additionalArguments;
+ }
+
+ @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
+ public Configuration(Configuration cfg) {
+ name = cfg.name;
+ buildDirectory = cfg.buildDirectory;
+ buildType = cfg.buildType;
+ backend = cfg.backend;
+ runArguments = cfg.runArguments;
+ runDirectory = cfg.runDirectory;
+ runExecutable = cfg.runExecutable;
+ wrapMode = cfg.wrapMode;
+ additionalArguments = new HashMap<>();
+ additionalArguments.putAll(cfg.additionalArguments);
+ }
+
+ public Configuration() {} // This is only here to make GSON happy
+
+ @Override
+ public String getDisplayName() {
+ return name;
+ }
+
+ public String getAdditionalArgumentsFor(String action) {
+ return additionalArguments.containsKey(action) ? additionalArguments.get(action) : "";
+ }
+
+ public String getBackend() {
+ return backend;
+ }
+
+ public String getBuildDirectory() {
+ return buildDirectory;
+ }
+
+ public String getBuildType() {
+ return buildType;
+ }
+
+ public String getCompileCommandsJsonPath() {
+ return Paths.get(getBuildDirectory(), "compile_commands.json").toString();
+ }
+
+ public String getRunArguments() {
+ return runArguments;
+ }
+
+ public String getRunDirectory() {
+ return runDirectory;
+ }
+
+ public String getRunExecutable() {
+ return runExecutable;
+ }
+
+ public String getWrapMode() {
+ return wrapMode;
+ }
+
+ public void setAdditionalArgumentsFor(String action, String arguments) {
+ additionalArguments.put(action, arguments);
+ }
+
+ public void setBackend(String backend) {
+ this.backend = backend;
+ }
+
+ public void setBuildDirectory(String directory) {
+ buildDirectory = directory;
+ }
+
+ public void setBuildType(String type) {
+ buildType = type;
+ }
+
+ public void setDisplayName(String name) {
+ this.name = name;
+ }
+
+ public void setRunArguments(String arguments) {
+ runArguments = arguments;
+ }
+
+ public void setRunDirectory(String directory) {
+ runDirectory = directory;
+ }
+
+ public void setRunExecutable(String executable) {
+ runExecutable = executable;
+ }
+
+ public void setWrapMode(String mode) {
+ wrapMode = mode;
+ }
+
+ public static Configuration getDefault() {
+ return new Configuration(
+ "default",
+ Paths.get(MesonProject.BUILD_DIRECTORY, "default").toString(),
+ "debug",
+ "ninja",
+ "default",
+ "",
+ "",
+ "",
+ new HashMap<>());
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ConfigurationProvider.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ConfigurationProvider.java
new file mode 100644
index 0000000..c71cda3
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ConfigurationProvider.java
@@ -0,0 +1,300 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.project;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+
+import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.netbeans.spi.project.ProjectConfigurationProvider;
+import org.netbeans.spi.project.ui.CustomizerProvider2;
+import org.openide.filesystems.FileChangeListener;
+import org.openide.filesystems.FileAttributeEvent;
+import org.openide.filesystems.FileEvent;
+import org.openide.filesystems.FileRenameEvent;
+import org.openide.filesystems.FileUtil;
+
+public class ConfigurationProvider implements ProjectConfigurationProvider<Configuration>
+{
+ private static final Logger LOGGER = Logger.getLogger(ConfigurationProvider.class.getName());
+ private static final String CONFIGURATIONS_JSON = "configurations.json"; // NOI18N
+
+ private final MesonProject project;
+ private Configuration activeConfiguration = null;
+ private List<Configuration> configurations = null;
+ private IntroCompilersJsonListener compilersListener = null;
+
+ public ConfigurationProvider(MesonProject project) {
+ this.project = project;
+
+ File configurationsFile = new File(getConfigurationsFilePath());
+
+ if (configurationsFile.exists()) {
+ try {
+ ConfigurationsFileContent content = new Gson().fromJson(new FileReader(configurationsFile), new TypeToken<ConfigurationsFileContent>(){}.getType());
+
+ if ((content != null) && (content.configurations != null)) {
+ configurations = content.configurations;
+
+ if (content.activeConfigurationName != null) {
+ for (Configuration c: configurations) {
+ if (content.activeConfigurationName.equals(c.getDisplayName())) {
+ activeConfiguration = c;
+ break;
+ }
+ }
+ }
+
+ if (activeConfiguration == null) {
+ final String defaultName = Configuration.getDefault().getDisplayName();
+
+ for (Configuration c: configurations) {
+ if (defaultName.equals(c.getDisplayName())) {
+ activeConfiguration = c;
+ break;
+ }
+ }
+ }
+
+ if ((activeConfiguration == null) && !configurations.isEmpty()) {
+ activeConfiguration = configurations.get(0);
+ }
+
+ if (activeConfiguration == null) {
+ activeConfiguration = Configuration.getDefault();
+ configurations.add(activeConfiguration);
+ }
+ }
+ }
+ catch (FileNotFoundException ex) {
+ LOGGER.log(Level.INFO, null, ex);
+ }
+ }
+
+ if (configurations == null) {
+ configurations = new ArrayList<>();
+ activeConfiguration = Configuration.getDefault();
+ configurations.add(activeConfiguration);
+ }
+
+ File compilersFile = getActiveIntroCompilersJsonPath(project, activeConfiguration).toFile();
+
+ if (compilersFile.exists()) {
+ updateLanguages(project, compilersFile);
+ }
+
+ FileUtil.addFileChangeListener(compilersListener = new IntroCompilersJsonListener(project), compilersFile);
+ }
+
+ public void add(Configuration configuration) {
+ configurations.add(configuration);
+ if (activeConfiguration == null) {
+ setActiveConfiguration(configuration);
+ }
+ }
+
+ @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
+ public void setConfigurations(List<Configuration> configurations) {
+ final String activeConfigurationName = getActiveConfiguration().getDisplayName();
+ this.configurations = configurations;
+ activeConfiguration = null;
+ for (Configuration cfg: configurations) {
+ if (activeConfigurationName.equals(cfg.getDisplayName())) {
+ setActiveConfiguration(cfg);
+ break;
+ }
+ }
+ if (activeConfiguration == null && !configurations.isEmpty()) {
+ setActiveConfiguration(configurations.get(0));
+ }
+ }
+
+ public synchronized void save() {
+ try {
+ Files.createDirectories(Paths.get(getConfigurationsFilePath()).getParent());
+
+ try (FileWriter writer = new FileWriter(getConfigurationsFilePath())) {
+ GsonBuilder builder = new GsonBuilder();
+ builder.setPrettyPrinting();
+ writer.write(builder.create().toJson(new ConfigurationsFileContent(activeConfiguration, configurations)));
+ }
+ }
+ catch (IOException ex) {
+ LOGGER.log(Level.WARNING, null, ex);
+ }
+ }
+
+ @Override
+ public Collection<Configuration> getConfigurations() {
+ return Collections.unmodifiableCollection(configurations);
+ }
+
+ @Override
+ public Configuration getActiveConfiguration() {
+ return activeConfiguration;
+ }
+
+ @Override
+ public void setActiveConfiguration(Configuration configuration) {
+ if (activeConfiguration != configuration) {
+ if ((activeConfiguration != null) && (compilersListener != null)) {
+ FileUtil.removeFileChangeListener(compilersListener, getActiveIntroCompilersJsonPath(project).toFile());
+ }
+
+ activeConfiguration = configuration;
+
+ File compilersFile = getActiveIntroCompilersJsonPath(project).toFile();
+
+ if (compilersFile.exists()) {
+ updateLanguages(project, compilersFile);
+ }
+
+ FileUtil.addFileChangeListener(compilersListener = new IntroCompilersJsonListener(project), compilersFile);
+ }
+ }
+
+ @Override
+ public boolean hasCustomizer() {
+ return true;
+ }
+
+ @Override
+ public void customize() {
+ project.getLookup().lookup(CustomizerProvider2.class).showCustomizer();
+ }
+
+ @Override
+ public boolean configurationsAffectAction(String command) {
+ return true;
+ }
+
+ @Override
+ public void addPropertyChangeListener(PropertyChangeListener lst) {
+ }
+
+ @Override
+ public void removePropertyChangeListener(PropertyChangeListener lst) {
+ }
+
+ private String getConfigurationsFilePath() {
+ return Paths.get(project.getProjectDirectory().getPath(), MesonProject.NBPROJECT_DIRECTORY, CONFIGURATIONS_JSON).toString();
+ }
+
+ private static Path getActiveIntroCompilersJsonPath(MesonProject project) {
+ return getActiveIntroCompilersJsonPath(project, project.getActiveConfiguration());
+ }
+
+ private static Path getActiveIntroCompilersJsonPath(MesonProject project, Configuration configuration) {
+ return Paths.get(project.getProjectDirectory().getPath(), configuration.getBuildDirectory(), MesonProject.COMPILERS_JSON);
+ }
+
+ private static final class ConfigurationsFileContent {
+ public String activeConfigurationName;
+ public List<Configuration> configurations;
+
+ public ConfigurationsFileContent() {}
+ public ConfigurationsFileContent(Configuration activeConfiguration, List<Configuration> configurations) {
+ this.activeConfigurationName = activeConfiguration.getDisplayName();
+ this.configurations = configurations;
+ }
+ };
+
+ private static final class IntroCompilersJsonListener implements FileChangeListener {
+ private final MesonProject project;
+
+ public IntroCompilersJsonListener(MesonProject project) {
+ this.project = project;
+ }
+
+ @Override
+ public void fileAttributeChanged(FileAttributeEvent e) {}
+
+ @Override
+ public void fileChanged(FileEvent e) {
+ updateLanguages(project);
+ }
+
+ @Override
+ public void fileDataCreated(FileEvent e) {
+ updateLanguages(project);
+ }
+
+ @Override
+ public void fileDeleted(FileEvent e) {}
+
+ @Override
+ public void fileFolderCreated(FileEvent e) {}
+
+ @Override
+ public void fileRenamed(FileRenameEvent e) {}
+ };
+
+ private static final class Compiler {
+ String id;
+ String[] exelist;
+ String[] linker_exelist;
+ String[] file_suffixes;
+ String default_suffix;
+ String version;
+ String full_version;
+ String linker_id;
+ };
+
+ private static void updateLanguages(MesonProject project) {
+ updateLanguages(project, getActiveIntroCompilersJsonPath(project).toFile());
+ }
+
+ private static void updateLanguages(MesonProject project, File compilersFile) {
+ try {
+ Map<String, Map<String, Compiler>> machines = new Gson().fromJson(new FileReader(compilersFile), new TypeToken<Map<String, Map<String, Compiler>>>(){}.getType());
+
+ if (machines != null) {
+ Map<String, Compiler> host = machines.get("host");
+ if (host != null) {
+ Set<String> languages = host.keySet();
+ if (!languages.isEmpty()) {
+ project.setLanguages(languages);
+ }
+ }
+ }
+ }
+ catch (FileNotFoundException ex) {
+ LOGGER.log(Level.INFO, null, ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/LineConvertorFactoryImpl.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/LineConvertorFactoryImpl.java
new file mode 100644
index 0000000..4a0c02e
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/LineConvertorFactoryImpl.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.project;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.netbeans.api.extexecution.ExecutionDescriptor.LineConvertorFactory;
+import org.netbeans.api.extexecution.print.ConvertedLine;
+import org.netbeans.api.extexecution.print.LineConvertor;
+import org.openide.cookies.LineCookie;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.text.Line;
+import org.openide.windows.OutputEvent;
+import org.openide.windows.OutputListener;
+
+public class LineConvertorFactoryImpl implements LineConvertorFactory
+{
+ @Override
+ public LineConvertor newLineConvertor()
+ {
+ return new MesonLineConvertor();
+ }
+
+ // This thing works for meson, gcc, and clang output. It might work for other things, but
+ // it would probably be best to use the toolchain appropriate instance of
+ // org.netbeans.modules.cnd.spi.toolchain.CompilerLineConvertor for compiler output.
+ private static final class MesonLineConvertor implements LineConvertor {
+ private static final Pattern ERROR_LINE = Pattern.compile("(.*):(\\d+):(\\d+):.*");
+ @Override
+ public List<ConvertedLine> convert(String line) {
+ Matcher matcher = ERROR_LINE.matcher(line);
+ if (matcher.matches()) {
+ String fileName = matcher.group(1);
+ int lineNum = Integer.parseInt(matcher.group(2)) - 1;
+ int columnNum = Integer.parseInt(matcher.group(3)) - 1;
+ return Collections.singletonList(ConvertedLine.forText(line, new OutputListener() {
+ @Override
+ public void outputLineSelected(OutputEvent ev) {}
+ @Override
+ public void outputLineAction(OutputEvent ev) {
+ FileObject file = FileUtil.toFileObject(new File(fileName));
+ if (file != null) {
+ LineCookie lc = file.getLookup().lookup(LineCookie.class);
+ lc.getLineSet().getCurrent(lineNum).show(Line.ShowOpenType.OPEN, Line.ShowVisibilityType.FOCUS, columnNum);
+ }
+ }
+ @Override
+ public void outputLineCleared(OutputEvent ev) {}
+ }));
+ }
+ return Collections.singletonList(ConvertedLine.forText(line, null));
+ }
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/LogicalViewProviderImpl.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/LogicalViewProviderImpl.java
new file mode 100644
index 0000000..6169307
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/LogicalViewProviderImpl.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.meson.project;
+
+import java.awt.Image;
+
+import javax.swing.Action;
+import org.netbeans.spi.project.ui.LogicalViewProvider;
+import org.netbeans.spi.project.ui.support.CommonProjectActions;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectNotFoundException;
+import org.openide.nodes.FilterNode;
+import org.openide.nodes.Node;
+import org.openide.util.ImageUtilities;
+import org.openide.util.lookup.Lookups;
+import org.openide.util.lookup.ProxyLookup;
+
+public class LogicalViewProviderImpl implements LogicalViewProvider {
+
+ private final MesonProject project;
+
+ public LogicalViewProviderImpl(MesonProject project) {
+ this.project = project;
+ }
+
+ @Override
+ public Node createLogicalView() {
+ try {
+ return new RootNode(DataObject.find(project.getProjectDirectory()).getNodeDelegate(), project);
+ } catch (DataObjectNotFoundException ex) {
+ return Node.EMPTY;
+ }
+ }
+
+ @Override
+ public Node findPath(Node root, Object target) {
+ return null; //XXX
+ }
+
+ private static class RootNode extends FilterNode {
+
+ public RootNode(Node delegate, MesonProject project) {
+ super(delegate, null, new ProxyLookup(delegate.getLookup(), Lookups.fixed(project)));
+ }
+
+ @Override
+ public Image getIcon(int type) {
+ return ImageUtilities.loadImage(MesonProject.ICON); // NOI18N
+ }
+
+ @Override
+ public Image getOpenedIcon(int type) {
+ return ImageUtilities.loadImage(MesonProject.OPEN_ICON); // NOI18N
+ }
+
+ @Override
+ public Action[] getActions(boolean param) {
+ return CommonProjectActions.forType(MesonProject.PROJECT_KEY); // NOI18N
+ }
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/MesonProject.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/MesonProject.java
new file mode 100644
index 0000000..0f65637
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/MesonProject.java
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.project;
+
+import java.beans.PropertyChangeListener;
+import java.nio.file.Paths;
+import java.util.Set;
+
+import javax.swing.Icon;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectInformation;
+import org.netbeans.modules.cnd.meson.project.ui.CustomizerProviderImpl;
+import org.netbeans.spi.project.ProjectState;
+import org.netbeans.spi.project.ui.PrivilegedTemplates;
+import org.netbeans.spi.project.ui.RecommendedTemplates;
+import org.openide.filesystems.FileObject;
+import org.openide.util.ImageUtilities;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+
+public class MesonProject implements Project {
+ public static final String PROJECT_KEY = "org-netbeans-modules-cnd-meson-project"; // NOI18N
+ public static final String NBPROJECT_DIRECTORY = ".netbeans"; // NOI18N
+ public static final String BUILD_DIRECTORY = ".netbeans/build"; // NOI18N
+ public static final String PROJECT_JSON = "project.json"; // NOI18N
+ public static final String ICON = "org/netbeans/modules/cnd/meson/resources/project_icon.png"; // NOI18N
+ public static final String OPEN_ICON = ICON;
+ public static final String INFO_DIRECTORY = "meson-info";
+ public static final String COMPILERS_JSON = Paths.get(INFO_DIRECTORY, "intro-compilers.json").toString();
+ public static final String MESON_INFO_JSON = Paths.get(INFO_DIRECTORY, "meson-info.json").toString();
+
+ private static final String C_LANGUAGE = "c";
+ private static final String CPP_LANGUAGE = "cpp";
+ private static final String FORTRAN_LANGUAGE = "fortran";
+ private static final String JAVA_LANGUAGE = "java";
+ private static final String RUST_LANGUAGE = "rust";
+
+ private final FileObject projectDirectory;
+ private final ProjectState state;
+ private final Lookup lookup;
+ private final ConfigurationProvider configurationProvider;
+ private Set<String> languages;
+
+ @Override
+ public FileObject getProjectDirectory() {
+ return projectDirectory;
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return lookup;
+ }
+
+ public ConfigurationProvider getConfigurationProvider() {
+ return configurationProvider;
+ }
+
+ public Configuration getActiveConfiguration() {
+ return configurationProvider.getActiveConfiguration();
+ }
+
+ public String getCompileCommandsJsonPathForActiveConfiguration() {
+ return Paths.get(getProjectDirectory().getPath(), configurationProvider.getActiveConfiguration().getCompileCommandsJsonPath()).toString();
+ }
+
+ public void setActiveConfiguration(Configuration configuration) {
+ configurationProvider.setActiveConfiguration(configuration);
+ }
+
+ public void setLanguages(Set<String> languages) {
+ this.languages = languages;
+ }
+
+ public boolean isC() { return hasLanguage(C_LANGUAGE); }
+ public boolean isCPP() { return hasLanguage(CPP_LANGUAGE); }
+ public boolean isFortran() { return hasLanguage(FORTRAN_LANGUAGE); }
+ public boolean isJava() { return hasLanguage(JAVA_LANGUAGE); }
+ public boolean isRust() { return hasLanguage(RUST_LANGUAGE); }
+
+ private boolean hasLanguage(String language) {
+ return languages != null && languages.contains(language);
+ }
+
+ @SuppressWarnings({"LeakingThisInConstructor", "this-escape"})
+ public MesonProject(FileObject projectDirectory, ProjectState state) {
+ this.projectDirectory = projectDirectory;
+ this.state = state;
+ this.configurationProvider = new ConfigurationProvider(this);
+ this.lookup = Lookups.fixed(new LogicalViewProviderImpl(this),
+ new ActionProviderImpl(this),
+ new CustomizerProviderImpl(this),
+ new RecommendedTemplatesImpl(this),
+ new PrivilegedTemplatesImpl(this),
+ new ProjectInfo(this),
+ configurationProvider,
+ this);
+ }
+
+ public static Icon getIcon() {
+ return ImageUtilities.image2Icon(ImageUtilities.loadImage(ICON));
+ }
+
+ private static class RecommendedTemplatesImpl implements RecommendedTemplates {
+ private static final String[] MESON_TYPES = new String[] {
+ "meson-types", // NOI18N
+ "simple-files", // NOI18N
+ };
+ private static final String[] C_TYPES = new String[] {
+ "c-types", // NOI18N
+ };
+ private static final String[] CPP_TYPES = new String[] {
+ "cpp-types", // NOI18N
+ };
+ private static final String[] FORTRAN_TYPES = new String[] {
+ "fortran-types", // NOI18N
+ };
+ private static final String[] JAVA_TYPES = new String[] {
+ "java-classes", // NOI18N
+ "java-main-class", // NOI18N
+ "java-forms", // NOI18N
+ "gui-java-application", // NOI18N
+ "java-beans", // NOI18N
+ "oasis-XML-catalogs", // NOI18N
+ "XML", // NOI18N
+ "junit", // NOI18N
+ };
+ private static final String[] RUST_TYPES = new String[] {
+ "rust", // NOI18N
+ "XML", // NOI18N
+ };
+
+ private final MesonProject project;
+
+ public RecommendedTemplatesImpl(MesonProject project) {
+ this.project = project;
+ }
+
+ @Override
+ public String[] getRecommendedTypes() {
+ String[] templates = MESON_TYPES;
+
+ if (project.isC()) {
+ templates = Utils.concatenate(templates, C_TYPES);
+ }
+
+ if (project.isCPP()) {
+ templates = Utils.concatenate(templates, CPP_TYPES);
+ }
+
+ if (project.isFortran()) {
+ templates = Utils.concatenate(templates, FORTRAN_TYPES);
+ }
+
+ if (project.isJava()) {
+ templates = Utils.concatenate(templates, JAVA_TYPES);
+ }
+
+ if (project.isRust()) {
+ templates = Utils.concatenate(templates, RUST_TYPES);
+ }
+
+ return templates;
+ }
+ }
+
+ private static class PrivilegedTemplatesImpl implements PrivilegedTemplates {
+ private static final String[] MESON_TEMPLATES = new String[] {
+ "Templates/meson/meson.build", // NOI18N
+ "Templates/meson/meson.options", // NOI18N
+ };
+ private static final String[] C_TEMPLATES = new String[] {
+ "Templates/cFiles/main.c", // NOI18N
+ "Templates/cFiles/file.c", // NOI18N
+ "Templates/cFiles/file.h", // NOI18N
+ };
+ private static final String[] CPP_TEMPLATES = new String[] {
+ "Templates/cppFiles/class.cc", // NOI18N
+ "Templates/cppFiles/main.cc", // NOI18N
+ "Templates/cppFiles/file.cc", // NOI18N
+ "Templates/cppFiles/file.h", // NOI18N
+ };
+ private static final String[] FORTRAN_TEMPLATES = new String[] {
+ "Templates/fortranFiles/fortranFreeFormatFile.f90", // NOI18N
+ };
+ private static final String[] JAVA_TEMPLATES = new String[] {
+ "Templates/Classes/Class.java", // NOI18N
+ "Templates/Classes/Interface.java", // NOI18N
+ "Templates/Other/properties.properties", // NOI18N
+ };
+ private static final String[] RUST_TEMPLATES = new String[] {
+ "Templates/rust/rust-file.rs", // NOI18N
+ };
+
+ private final MesonProject project;
+
+ public PrivilegedTemplatesImpl(MesonProject project) {
+ this.project = project;
+ }
+
+ @Override
+ public String[] getPrivilegedTemplates() {
+ String[] templates = MESON_TEMPLATES;
+
+ if (project.isC()) {
+ templates = Utils.concatenate(templates, C_TEMPLATES);
+ }
+
+ if (project.isCPP()) {
+ templates = Utils.concatenate(templates, CPP_TEMPLATES);
+ }
+
+ if (project.isFortran()) {
+ templates = Utils.concatenate(templates, FORTRAN_TEMPLATES);
+ }
+
+ if (project.isJava()) {
+ templates = Utils.concatenate(templates, JAVA_TEMPLATES);
+ }
+
+ if (project.isRust()) {
+ templates = Utils.concatenate(templates, RUST_TEMPLATES);
+ }
+
+ return templates;
+ }
+ }
+
+ private static final class ProjectInfo implements ProjectInformation {
+ private final Project project;
+
+ public ProjectInfo(Project project) {
+ this.project = project;
+ }
+
+ @Override
+ public String getName() {
+ return project.getProjectDirectory().getNameExt();
+ }
+
+ @Override
+ public String getDisplayName() {
+ return project.getProjectDirectory().getNameExt();
+ }
+
+ @Override
+ public Icon getIcon() {
+ return MesonProject.getIcon();
+ }
+
+ @Override
+ public Project getProject() {
+ return project;
+ }
+
+ @Override
+ public void addPropertyChangeListener(PropertyChangeListener listener) {}
+
+ @Override
+ public void removePropertyChangeListener(PropertyChangeListener listener) {}
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/MesonProjectFactory.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/MesonProjectFactory.java
new file mode 100644
index 0000000..f5184c9
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/MesonProjectFactory.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.project;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.netbeans.api.lexer.InputAttributes;
+import org.netbeans.api.lexer.TokenHierarchy;
+import org.netbeans.api.lexer.TokenSequence;
+import org.netbeans.api.lexer.TokenUtilities;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectManager;
+import org.netbeans.modules.cnd.meson.lexer.MesonBuildTokenId;
+import org.netbeans.spi.project.ProjectFactory;
+import org.netbeans.spi.project.ProjectFactory2;
+import org.netbeans.spi.project.ProjectState;
+import org.openide.filesystems.FileObject;
+import org.openide.util.lookup.ServiceProvider;
+
+@ServiceProvider(service=ProjectFactory.class, position = 200)
+public class MesonProjectFactory implements ProjectFactory2 {
+ private static final Logger LOGGER = Logger.getLogger(MesonProjectFactory.class.getName());
+
+ @Override
+ public ProjectManager.Result isProject2(FileObject projectDirectory) {
+ FileObject script = projectDirectory.getFileObject("meson.build"); // NOI18N
+ if ((script != null) && script.isValid()) {
+ // The first statement in a top-level meson.build file must be a
+ // call to project(...). Leverage that to avoid detecting meson.build
+ // files in subdirectories as meson projects.
+ try {
+ TokenSequence<MesonBuildTokenId> tokens =
+ TokenHierarchy.create(
+ script.asText(),
+ false,
+ MesonBuildTokenId.language(),
+ Stream.of(MesonBuildTokenId.WHITESPACE, MesonBuildTokenId.COMMENT).collect(Collectors.toSet()),
+ new InputAttributes()).tokenSequence(MesonBuildTokenId.language());
+
+ if (tokens.moveNext() && TokenUtilities.equals(tokens.token().text(), "project")) {
+ return new ProjectManager.Result(null, MesonProjectType.TYPE, MesonProject.getIcon());
+ }
+ }
+ catch (IOException ex) {
+ LOGGER.log(Level.INFO, null, ex);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isProject(FileObject projectDirectory) {
+ return isProject2(projectDirectory) != null;
+ }
+
+ @Override
+ public Project loadProject(FileObject projectDirectory, ProjectState state) throws IOException {
+ if (isProject(projectDirectory)) {
+ return new MesonProject(projectDirectory, state);
+ }
+ return null;
+ }
+
+ @Override
+ public void saveProject(Project project) throws IOException, ClassCastException {
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/MesonProjectType.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/MesonProjectType.java
new file mode 100644
index 0000000..7da73db
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/MesonProjectType.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.cnd.meson.project;
+
+import org.netbeans.modules.cnd.api.project.NativeProjectType;
+
+public class MesonProjectType implements NativeProjectType {
+ public static final String TYPE = "org.netbeans.modules.cnd.meson.project"; // NOI18N
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String getPrimaryConfigurationDataElementName(boolean shared) {
+ return "data";
+ }
+
+ @Override
+ public String getPrimaryConfigurationDataElementNamespace(boolean shared) {
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/Utils.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/Utils.java
new file mode 100644
index 0000000..2ca880b
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/Utils.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.meson.project;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class Utils {
+ public static String encode(List<List<String>> toSave) {
+ return toSave.stream().map(c -> escape(c.stream().map(p -> escape(p)).collect(Collectors.joining(" ")))).collect(Collectors.joining(" "));
+ }
+
+ public static List<List<String>> decode(String toDecode) {
+ List<List<String>> result = new ArrayList<>();
+ for (String commandDesc : toDecode.split(" ")) {
+ List<String> command = new ArrayList<>();
+ for (String paramDesc : unescape(commandDesc).split(" ")) {
+ command.add(unescape(paramDesc));
+ }
+ result.add(command);
+ }
+ return result;
+ }
+
+ public static boolean isEmpty(String s) {
+ return s == null || s.isEmpty();
+ }
+
+ public static String[] concatenate(String[] a1, String[] a2) {
+ String[] combined = null;
+
+ if (a1 != null) {
+ combined = Arrays.copyOf(a1, a1.length + ((a2 != null) ? a2.length : 0));
+ }
+
+ if (a2 != null) {
+ if (combined != null) {
+ System.arraycopy(a2, 0, combined, a1.length, a2.length);
+ }
+ else {
+ combined = Arrays.copyOf(a2, a2.length);
+ }
+ }
+
+ return combined;
+ }
+
+ private static String escape(String s) {
+ return s.replace("_", "_u_").replace(" ", "_s_");
+ }
+
+ private static String unescape(String s) {
+ return s.replace("_s_", " ").replace("_u_", "_");
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ui/Bundle.properties b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ui/Bundle.properties
new file mode 100644
index 0000000..b308c9b
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ui/Bundle.properties
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+ConfigurationPanel.backendLabel.text=Backend
+ConfigurationPanel.wrapModeLabel.text=Wrap Mode
+ConfigurationPanel.buildTypeLabel.text=Build Type
+ConfigurationPanel.buildDirectoryTextField.text=build
+ConfigurationPanel.buildDirectoryLabel.text=Build Directory
+ConfigurationPanel.buildDirectoryBrowseButton.text=...
+ConfigurationPanel.configurationLabel.text=Configuration
+ConfigurationPanel.newConfigurationButton.text=New
+ConfigurationPanel.renameConfigurationButton.text=Rename
+ConfigurationPanel.deleteConfigurationButton.text=Delete
+ConfigurationPanel.runExecutableLabel.text=Run Executable
+ConfigurationPanel.runExecutableTextField.text=
+ConfigurationPanel.runExecutableBrowseButton.text=...
+ConfigurationPanel.runArgumentsLabel.text=Run Arguments
+ConfigurationPanel.runDirectoryTextField.text=
+ConfigurationPanel.runDirectoryBrowseButton.text=...
+ConfigurationPanel.runDirectoryLabel.text=Run Directory
+ConfigurationPanel.runArgumentsTextField.text=
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ui/ConfigurationPanel.form b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ui/ConfigurationPanel.form
new file mode 100644
index 0000000..8a4f0e0
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ui/ConfigurationPanel.form
@@ -0,0 +1,435 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+ <AuxValues>
+ <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+ <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+ <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+ <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+ <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+ <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+ <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+ <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+ <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+ </AuxValues>
+
+ <Layout>
+ <DimensionLayout dim="0">
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Group type="102" attributes="0">
+ <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Group type="102" attributes="0">
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Component id="runExecutableLabel" min="-2" max="-2" attributes="0"/>
+ <Component id="runArgumentsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+ <Component id="runDirectoryLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <EmptySpace min="-2" pref="21" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Component id="runArgumentsTextField" alignment="1" max="32767" attributes="0"/>
+ <Component id="runDirectoryTextField" max="32767" attributes="0"/>
+ <Component id="runExecutableTextField" alignment="0" max="32767" attributes="0"/>
+ </Group>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="0" max="-2" attributes="0">
+ <Component id="runExecutableBrowseButton" max="32767" attributes="0"/>
+ <Component id="runDirectoryBrowseButton" max="32767" attributes="0"/>
+ </Group>
+ </Group>
+ <Component id="jSeparator2" alignment="0" max="32767" attributes="0"/>
+ <Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
+ <Group type="102" alignment="0" attributes="0">
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Component id="buildDirectoryLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+ <Component id="buildTypeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+ <Component id="backendLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+ <Component id="configurationLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+ <Component id="wrapModeLabel" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Group type="102" attributes="0">
+ <EmptySpace min="-2" pref="27" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Component id="buildDirectoryTextField" max="32767" attributes="0"/>
+ <Component id="buildTypeComboBox" alignment="0" max="32767" attributes="0"/>
+ <Component id="backendComboBox" max="32767" attributes="0"/>
+ <Component id="wrapModeComboBox" alignment="0" max="32767" attributes="0"/>
+ </Group>
+ <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
+ <Component id="buildDirectoryBrowseButton" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <Group type="102" attributes="0">
+ <EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
+ <Component id="configurationComboBox" pref="190" max="32767" attributes="0"/>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Component id="newConfigurationButton" min="-2" pref="78" max="-2" attributes="0"/>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Component id="renameConfigurationButton" min="-2" max="-2" attributes="0"/>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Component id="deleteConfigurationButton" min="-2" pref="103" max="-2" attributes="0"/>
+ </Group>
+ </Group>
+ </Group>
+ <Component id="jSeparator1" alignment="0" max="32767" attributes="0"/>
+ </Group>
+ <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
+ </Group>
+ </Group>
+ </DimensionLayout>
+ <DimensionLayout dim="1">
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Group type="102" alignment="0" attributes="0">
+ <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="3" attributes="0">
+ <Component id="configurationLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="configurationComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="newConfigurationButton" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="deleteConfigurationButton" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="renameConfigurationButton" alignment="3" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Component id="jSeparator1" min="-2" pref="10" max="-2" attributes="0"/>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="3" attributes="0">
+ <Component id="buildDirectoryTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="buildDirectoryLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="buildDirectoryBrowseButton" alignment="3" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="1" attributes="0">
+ <Group type="102" attributes="0">
+ <Group type="103" groupAlignment="3" attributes="0">
+ <Component id="buildTypeLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="buildTypeComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <EmptySpace type="separate" min="-2" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="3" attributes="0">
+ <Component id="backendLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="backendComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="3" attributes="0">
+ <Component id="wrapModeLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="wrapModeComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Component id="jScrollPane1" min="-2" pref="115" max="-2" attributes="0"/>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Component id="jSeparator2" min="-2" pref="10" max="-2" attributes="0"/>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="3" attributes="0">
+ <Component id="runExecutableTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="runExecutableLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="3" attributes="0">
+ <Component id="runArgumentsTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="runArgumentsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="3" attributes="0">
+ <Component id="runDirectoryTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="runDirectoryLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+ </Group>
+ </Group>
+ <Group type="102" attributes="0">
+ <Component id="runExecutableBrowseButton" min="-2" max="-2" attributes="0"/>
+ <EmptySpace min="70" pref="70" max="-2" attributes="0"/>
+ <Component id="runDirectoryBrowseButton" min="-2" max="-2" attributes="0"/>
+ </Group>
+ </Group>
+ <EmptySpace pref="20" max="32767" attributes="0"/>
+ </Group>
+ </Group>
+ </DimensionLayout>
+ </Layout>
+ <SubComponents>
+ <Component class="javax.swing.JTextField" name="buildDirectoryTextField">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.buildDirectoryTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[32767, 32767]"/>
+ </Property>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[160, 34]"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JLabel" name="buildDirectoryLabel">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.buildDirectoryLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JButton" name="buildDirectoryBrowseButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.buildDirectoryBrowseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buildDirectoryBrowseButtonActionPerformed"/>
+ </Events>
+ </Component>
+ <Component class="javax.swing.JLabel" name="buildTypeLabel">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.buildTypeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JComboBox" name="buildTypeComboBox">
+ <Properties>
+ <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+ <StringArray count="6">
+ <StringItem index="0" value="plain"/>
+ <StringItem index="1" value="debug"/>
+ <StringItem index="2" value="debugoptimized"/>
+ <StringItem index="3" value="release"/>
+ <StringItem index="4" value="minsize"/>
+ <StringItem index="5" value="custom"/>
+ </StringArray>
+ </Property>
+ <Property name="selectedIndex" type="int" value="1"/>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[80, 34]"/>
+ </Property>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[160, 34]"/>
+ </Property>
+ </Properties>
+ <AuxValues>
+ <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
+ </AuxValues>
+ </Component>
+ <Component class="javax.swing.JLabel" name="wrapModeLabel">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.wrapModeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JComboBox" name="wrapModeComboBox">
+ <Properties>
+ <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+ <StringArray count="5">
+ <StringItem index="0" value="default"/>
+ <StringItem index="1" value="nofallback"/>
+ <StringItem index="2" value="nodownload"/>
+ <StringItem index="3" value="forcefallback"/>
+ <StringItem index="4" value="nopromote"/>
+ </StringArray>
+ </Property>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[80, 34]"/>
+ </Property>
+ </Properties>
+ <AuxValues>
+ <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
+ </AuxValues>
+ </Component>
+ <Component class="javax.swing.JLabel" name="backendLabel">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.backendLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JComboBox" name="backendComboBox">
+ <Properties>
+ <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+ <StringArray count="11">
+ <StringItem index="0" value="ninja"/>
+ <StringItem index="1" value="vs"/>
+ <StringItem index="2" value="vs2010"/>
+ <StringItem index="3" value="vs2012"/>
+ <StringItem index="4" value="vs2013"/>
+ <StringItem index="5" value="vs2015"/>
+ <StringItem index="6" value="vs2017"/>
+ <StringItem index="7" value="vs2019"/>
+ <StringItem index="8" value="vs2022"/>
+ <StringItem index="9" value="xcode"/>
+ <StringItem index="10" value="none"/>
+ </StringArray>
+ </Property>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[80, 34]"/>
+ </Property>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[160, 34]"/>
+ </Property>
+ </Properties>
+ <AuxValues>
+ <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
+ </AuxValues>
+ </Component>
+ <Component class="javax.swing.JLabel" name="configurationLabel">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.configurationLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JComboBox" name="configurationComboBox">
+ <Properties>
+ <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+ <Connection code="configurationComboBoxModel" type="code"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="configurationComboBoxItemStateChanged"/>
+ </Events>
+ <AuxValues>
+ <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
+ </AuxValues>
+ </Component>
+ <Component class="javax.swing.JButton" name="newConfigurationButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.newConfigurationButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newConfigurationButtonActionPerformed"/>
+ </Events>
+ </Component>
+ <Component class="javax.swing.JButton" name="deleteConfigurationButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.deleteConfigurationButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deleteConfigurationButtonActionPerformed"/>
+ </Events>
+ </Component>
+ <Component class="javax.swing.JButton" name="renameConfigurationButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.renameConfigurationButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="renameConfigurationButtonActionPerformed"/>
+ </Events>
+ </Component>
+ <Component class="javax.swing.JSeparator" name="jSeparator1">
+ </Component>
+ <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+ <AuxValues>
+ <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+ </AuxValues>
+
+ <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+ <SubComponents>
+ <Component class="javax.swing.JTable" name="additionalArgumentsTable">
+ <Properties>
+ <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor">
+ <Table columnCount="2" rowCount="3">
+ <Column editable="false" title="Command" type="java.lang.String">
+ <Data value="setup"/>
+ <Data value="compile"/>
+ <Data value="test"/>
+ </Column>
+ <Column editable="true" title="Additional Arguments" type="java.lang.String"/>
+ </Table>
+ </Property>
+ <Property name="autoResizeMode" type="int" value="3"/>
+ </Properties>
+ <AuxValues>
+ <AuxValue name="JavaCodeGenerator_InitCodePost" type="java.lang.String" value="additionalArgumentsTable.getColumnModel().getColumn(0).setMinWidth(100);
additionalArgumentsTable.getColumnModel().getColumn(0).setMaxWidth(150);"/>
+ </AuxValues>
+ </Component>
+ </SubComponents>
+ </Container>
+ <Component class="javax.swing.JSeparator" name="jSeparator2">
+ </Component>
+ <Component class="javax.swing.JLabel" name="runExecutableLabel">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.runExecutableLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JTextField" name="runExecutableTextField">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.runExecutableTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JButton" name="runExecutableBrowseButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.runExecutableBrowseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="runExecutableBrowseButtonActionPerformed"/>
+ </Events>
+ </Component>
+ <Component class="javax.swing.JLabel" name="runArgumentsLabel">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.runArgumentsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JTextField" name="runArgumentsTextField">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.runArgumentsTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JLabel" name="runDirectoryLabel">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.runDirectoryLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JButton" name="runDirectoryBrowseButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.runDirectoryBrowseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="runDirectoryBrowseButtonActionPerformed"/>
+ </Events>
+ </Component>
+ <Component class="javax.swing.JTextField" name="runDirectoryTextField">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/cnd/meson/project/ui/Bundle.properties" key="ConfigurationPanel.runDirectoryTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ </SubComponents>
+</Form>
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ui/ConfigurationPanel.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ui/ConfigurationPanel.java
new file mode 100644
index 0000000..41cd95f
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ui/ConfigurationPanel.java
@@ -0,0 +1,688 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.meson.project.ui;
+
+import java.awt.event.ItemEvent;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.ComboBoxModel;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+import static org.netbeans.modules.cnd.meson.project.ActionProviderImpl.COMMAND_SETUP;
+import org.netbeans.modules.cnd.meson.project.Configuration;
+import org.netbeans.modules.cnd.meson.project.ConfigurationProvider;
+import org.netbeans.modules.cnd.meson.project.MesonProject;
+import static org.netbeans.spi.project.ActionProvider.COMMAND_BUILD;
+import static org.netbeans.spi.project.ActionProvider.COMMAND_TEST;
+import org.netbeans.spi.project.ui.support.ProjectCustomizer;
+import org.openide.util.Lookup;
+
+
+/**
+ *
+ */
+public class ConfigurationPanel extends javax.swing.JPanel
+{
+
+ /**
+ * Creates new form MesonProjectOptionsPanel
+ */
+ public ConfigurationPanel(String projectRoot)
+ {
+ this.projectRoot = projectRoot;
+ initComponents();
+ }
+
+ /**
+ * This method is called from within the constructor to initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is always
+ * regenerated by the Form Editor.
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+ private void initComponents()
+ {
+
+ buildDirectoryTextField = new javax.swing.JTextField();
+ buildDirectoryLabel = new javax.swing.JLabel();
+ buildDirectoryBrowseButton = new javax.swing.JButton();
+ buildTypeLabel = new javax.swing.JLabel();
+ buildTypeComboBox = new javax.swing.JComboBox<>();
+ wrapModeLabel = new javax.swing.JLabel();
+ wrapModeComboBox = new javax.swing.JComboBox<>();
+ backendLabel = new javax.swing.JLabel();
+ backendComboBox = new javax.swing.JComboBox<>();
+ configurationLabel = new javax.swing.JLabel();
+ configurationComboBox = new javax.swing.JComboBox<>();
+ newConfigurationButton = new javax.swing.JButton();
+ deleteConfigurationButton = new javax.swing.JButton();
+ renameConfigurationButton = new javax.swing.JButton();
+ jSeparator1 = new javax.swing.JSeparator();
+ jScrollPane1 = new javax.swing.JScrollPane();
+ additionalArgumentsTable = new javax.swing.JTable();
+ jSeparator2 = new javax.swing.JSeparator();
+ runExecutableLabel = new javax.swing.JLabel();
+ runExecutableTextField = new javax.swing.JTextField();
+ runExecutableBrowseButton = new javax.swing.JButton();
+ runArgumentsLabel = new javax.swing.JLabel();
+ runArgumentsTextField = new javax.swing.JTextField();
+ runDirectoryLabel = new javax.swing.JLabel();
+ runDirectoryBrowseButton = new javax.swing.JButton();
+ runDirectoryTextField = new javax.swing.JTextField();
+
+ buildDirectoryTextField.setText(org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.buildDirectoryTextField.text")); // NOI18N
+ buildDirectoryTextField.setMaximumSize(new java.awt.Dimension(32767, 32767));
+ buildDirectoryTextField.setPreferredSize(new java.awt.Dimension(160, 34));
+
+ org.openide.awt.Mnemonics.setLocalizedText(buildDirectoryLabel, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.buildDirectoryLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(buildDirectoryBrowseButton, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.buildDirectoryBrowseButton.text")); // NOI18N
+ buildDirectoryBrowseButton.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(java.awt.event.ActionEvent evt)
+ {
+ buildDirectoryBrowseButtonActionPerformed(evt);
+ }
+ });
+
+ org.openide.awt.Mnemonics.setLocalizedText(buildTypeLabel, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.buildTypeLabel.text")); // NOI18N
+
+ buildTypeComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "plain", "debug", "debugoptimized", "release", "minsize", "custom" }));
+ buildTypeComboBox.setSelectedIndex(1);
+ buildTypeComboBox.setMinimumSize(new java.awt.Dimension(80, 34));
+ buildTypeComboBox.setPreferredSize(new java.awt.Dimension(160, 34));
+
+ org.openide.awt.Mnemonics.setLocalizedText(wrapModeLabel, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.wrapModeLabel.text")); // NOI18N
+
+ wrapModeComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "default", "nofallback", "nodownload", "forcefallback", "nopromote" }));
+ wrapModeComboBox.setMinimumSize(new java.awt.Dimension(80, 34));
+
+ org.openide.awt.Mnemonics.setLocalizedText(backendLabel, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.backendLabel.text")); // NOI18N
+
+ backendComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "ninja", "vs", "vs2010", "vs2012", "vs2013", "vs2015", "vs2017", "vs2019", "vs2022", "xcode", "none" }));
+ backendComboBox.setMinimumSize(new java.awt.Dimension(80, 34));
+ backendComboBox.setPreferredSize(new java.awt.Dimension(160, 34));
+
+ org.openide.awt.Mnemonics.setLocalizedText(configurationLabel, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.configurationLabel.text")); // NOI18N
+
+ configurationComboBox.setModel(configurationComboBoxModel);
+ configurationComboBox.addItemListener(new java.awt.event.ItemListener()
+ {
+ public void itemStateChanged(java.awt.event.ItemEvent evt)
+ {
+ configurationComboBoxItemStateChanged(evt);
+ }
+ });
+
+ org.openide.awt.Mnemonics.setLocalizedText(newConfigurationButton, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.newConfigurationButton.text")); // NOI18N
+ newConfigurationButton.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(java.awt.event.ActionEvent evt)
+ {
+ newConfigurationButtonActionPerformed(evt);
+ }
+ });
+
+ org.openide.awt.Mnemonics.setLocalizedText(deleteConfigurationButton, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.deleteConfigurationButton.text")); // NOI18N
+ deleteConfigurationButton.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(java.awt.event.ActionEvent evt)
+ {
+ deleteConfigurationButtonActionPerformed(evt);
+ }
+ });
+
+ org.openide.awt.Mnemonics.setLocalizedText(renameConfigurationButton, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.renameConfigurationButton.text")); // NOI18N
+ renameConfigurationButton.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(java.awt.event.ActionEvent evt)
+ {
+ renameConfigurationButtonActionPerformed(evt);
+ }
+ });
+
+ additionalArgumentsTable.setModel(new javax.swing.table.DefaultTableModel(
+ new Object [][]
+ {
+ {"setup", null},
+ {"compile", null},
+ {"test", null}
+ },
+ new String []
+ {
+ "Command", "Additional Arguments"
+ }
+ )
+ {
+ Class[] types = new Class []
+ {
+ java.lang.String.class, java.lang.String.class
+ };
+ boolean[] canEdit = new boolean []
+ {
+ false, true
+ };
+
+ public Class getColumnClass(int columnIndex)
+ {
+ return types [columnIndex];
+ }
+
+ public boolean isCellEditable(int rowIndex, int columnIndex)
+ {
+ return canEdit [columnIndex];
+ }
+ });
+ additionalArgumentsTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_LAST_COLUMN);
+ additionalArgumentsTable.getColumnModel().getColumn(0).setMinWidth(100);
+ additionalArgumentsTable.getColumnModel().getColumn(0).setMaxWidth(150);
+ jScrollPane1.setViewportView(additionalArgumentsTable);
+
+ org.openide.awt.Mnemonics.setLocalizedText(runExecutableLabel, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.runExecutableLabel.text")); // NOI18N
+
+ runExecutableTextField.setText(org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.runExecutableTextField.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(runExecutableBrowseButton, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.runExecutableBrowseButton.text")); // NOI18N
+ runExecutableBrowseButton.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(java.awt.event.ActionEvent evt)
+ {
+ runExecutableBrowseButtonActionPerformed(evt);
+ }
+ });
+
+ org.openide.awt.Mnemonics.setLocalizedText(runArgumentsLabel, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.runArgumentsLabel.text")); // NOI18N
+
+ runArgumentsTextField.setText(org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.runArgumentsTextField.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(runDirectoryLabel, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.runDirectoryLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(runDirectoryBrowseButton, org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.runDirectoryBrowseButton.text")); // NOI18N
+ runDirectoryBrowseButton.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(java.awt.event.ActionEvent evt)
+ {
+ runDirectoryBrowseButtonActionPerformed(evt);
+ }
+ });
+
+ runDirectoryTextField.setText(org.openide.util.NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.runDirectoryTextField.text")); // NOI18N
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+ this.setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addGap(20, 20, 20)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(runExecutableLabel)
+ .addComponent(runArgumentsLabel)
+ .addComponent(runDirectoryLabel))
+ .addGap(21, 21, 21)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(runArgumentsTextField, javax.swing.GroupLayout.Alignment.TRAILING)
+ .addComponent(runDirectoryTextField)
+ .addComponent(runExecutableTextField))
+ .addGap(18, 18, 18)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addComponent(runExecutableBrowseButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(runDirectoryBrowseButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+ .addComponent(jSeparator2)
+ .addComponent(jScrollPane1)
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(buildDirectoryLabel)
+ .addComponent(buildTypeLabel)
+ .addComponent(backendLabel)
+ .addComponent(configurationLabel)
+ .addComponent(wrapModeLabel))
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addGap(27, 27, 27)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(buildDirectoryTextField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(buildTypeComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(backendComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(wrapModeComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addGap(18, 18, 18)
+ .addComponent(buildDirectoryBrowseButton))
+ .addGroup(layout.createSequentialGroup()
+ .addGap(26, 26, 26)
+ .addComponent(configurationComboBox, 0, 190, Short.MAX_VALUE)
+ .addGap(18, 18, 18)
+ .addComponent(newConfigurationButton, javax.swing.GroupLayout.PREFERRED_SIZE, 78, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(18, 18, 18)
+ .addComponent(renameConfigurationButton)
+ .addGap(18, 18, 18)
+ .addComponent(deleteConfigurationButton, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE))))
+ .addComponent(jSeparator1))
+ .addGap(20, 20, 20))
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addGap(20, 20, 20)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(configurationLabel)
+ .addComponent(configurationComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(newConfigurationButton)
+ .addComponent(deleteConfigurationButton)
+ .addComponent(renameConfigurationButton))
+ .addGap(18, 18, 18)
+ .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(18, 18, 18)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(buildDirectoryTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(buildDirectoryLabel)
+ .addComponent(buildDirectoryBrowseButton))
+ .addGap(18, 18, 18)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(buildTypeLabel)
+ .addComponent(buildTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(18, 18, 18)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(backendLabel)
+ .addComponent(backendComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(18, 18, 18)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(wrapModeLabel)
+ .addComponent(wrapModeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(18, 18, 18)
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 115, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(18, 18, 18)
+ .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(18, 18, 18)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(runExecutableTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(runExecutableLabel))
+ .addGap(18, 18, 18)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(runArgumentsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(runArgumentsLabel))
+ .addGap(18, 18, 18)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(runDirectoryTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(runDirectoryLabel)))
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(runExecutableBrowseButton)
+ .addGap(70, 70, 70)
+ .addComponent(runDirectoryBrowseButton)))
+ .addContainerGap(20, Short.MAX_VALUE))
+ );
+ }// </editor-fold>//GEN-END:initComponents
+
+ private void renameConfigurationButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_renameConfigurationButtonActionPerformed
+ {//GEN-HEADEREND:event_renameConfigurationButtonActionPerformed
+ final String oldName = configurationComboBox.getSelectedItem().toString();
+
+ String newName =
+ (String)JOptionPane.showInputDialog(
+ this,
+ "Please enter a new name for the \"" + oldName + "\" configuration.",
+ "Rename Configuration",
+ JOptionPane.PLAIN_MESSAGE,
+ null,
+ null,
+ oldName);
+
+ if ((newName != null) && !newName.equals(oldName)) {
+ boolean alreadyExists = false;
+ for (Configuration cfg: configurations) {
+ if (newName.equals(cfg.getDisplayName())) {
+ alreadyExists = true;
+ break;
+ }
+ }
+ if (!alreadyExists) {
+ for (Configuration cfg: configurations) {
+ if (oldName.equals(cfg.getDisplayName())) {
+ cfg.setDisplayName(newName);
+ if (cfg.getBuildDirectory().equals(Paths.get(MesonProject.BUILD_DIRECTORY, oldName).toString())) {
+ cfg.setBuildDirectory(Paths.get(MesonProject.BUILD_DIRECTORY, newName).toString());
+ buildDirectoryTextField.setText(cfg.getBuildDirectory());
+ }
+ configurationComboBoxModel.setSelectedItem(newName);
+ configurationComboBoxModel.configurationsChanged();
+ break;
+ }
+ }
+ }
+ else {
+ JOptionPane.showMessageDialog(
+ this,
+ "Failed to rename configuration because a configuration named \"" + newName + "\" already exsits.",
+ "Rename Configuration Failed",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }//GEN-LAST:event_renameConfigurationButtonActionPerformed
+
+ private void buildDirectoryBrowseButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_buildDirectoryBrowseButtonActionPerformed
+ {//GEN-HEADEREND:event_buildDirectoryBrowseButtonActionPerformed
+ JFileChooser chooser = new JFileChooser();
+ chooser.setSelectedFile(Paths.get(projectRoot, buildDirectoryTextField.getText()).toFile());
+ chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ chooser.setFileHidingEnabled(false);
+ final int result = chooser.showDialog(this, "Select");
+ if (result == JFileChooser.APPROVE_OPTION) {
+ buildDirectoryTextField.setText(
+ Paths.get(projectRoot).relativize(chooser.getSelectedFile().toPath()).toString());
+ }
+ }//GEN-LAST:event_buildDirectoryBrowseButtonActionPerformed
+
+ private void configurationComboBoxItemStateChanged(java.awt.event.ItemEvent evt)//GEN-FIRST:event_configurationComboBoxItemStateChanged
+ {//GEN-HEADEREND:event_configurationComboBoxItemStateChanged
+ if (evt.getStateChange() == ItemEvent.SELECTED) {
+ final String selectedCfg = evt.getItem().toString();
+
+ for (Configuration cfg: configurations) {
+ if (selectedCfg.equals(cfg.getDisplayName())) {
+ toUI(cfg);
+ break;
+ }
+ }
+ }
+ else if (evt.getStateChange() == ItemEvent.DESELECTED) {
+ final String selectedCfg = evt.getItem().toString();
+
+ for (Configuration cfg: configurations) {
+ if (selectedCfg.equals(cfg.getDisplayName())) {
+ fromUI(cfg);
+ break;
+ }
+ }
+ }
+ }//GEN-LAST:event_configurationComboBoxItemStateChanged
+
+ private void newConfigurationButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_newConfigurationButtonActionPerformed
+ {//GEN-HEADEREND:event_newConfigurationButtonActionPerformed
+ String cfgName =
+ JOptionPane.showInputDialog(
+ this,
+ "Please enter a name for the new configuration.",
+ "New Configuration",
+ JOptionPane.PLAIN_MESSAGE);
+
+ if (cfgName != null) {
+ boolean alreadyExists = false;
+ for (Configuration cfg: configurations) {
+ if (cfgName.equals(cfg.getDisplayName())) {
+ alreadyExists = true;
+ break;
+ }
+ }
+ if (!alreadyExists) {
+ Configuration cfg = Configuration.getDefault();
+ cfg.setDisplayName(cfgName);
+ cfg.setBuildDirectory(Paths.get(MesonProject.BUILD_DIRECTORY, cfgName).toString());
+ configurations.add(cfg);
+ configurationComboBoxModel.configurationsChanged();
+ configurationComboBox.setSelectedItem(cfgName);
+ }
+ else {
+ JOptionPane.showMessageDialog(
+ this,
+ "Failed to create new configuration because a configuration named \"" + cfgName + "\" already exsits.",
+ "Create Configuration Failed",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }//GEN-LAST:event_newConfigurationButtonActionPerformed
+
+ private void deleteConfigurationButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_deleteConfigurationButtonActionPerformed
+ {//GEN-HEADEREND:event_deleteConfigurationButtonActionPerformed
+ final String cfgName = configurationComboBox.getSelectedItem().toString();
+
+ if (configurations.size() > 1) {
+ for (Configuration cfg: configurations) {
+ if (cfgName.equals(cfg.getDisplayName())) {
+ configurations.remove(cfg);
+ configurationComboBoxModel.setSelectedItem(configurations.get(0).getDisplayName());
+ configurationComboBoxModel.configurationsChanged();
+ toUI(configurations.get(0));
+ }
+ }
+ }
+ else {
+ JOptionPane.showMessageDialog(
+ this,
+ "Cannot delete the \"" + cfgName + "\" configuration because it's the last one and at least one configuration must exist.",
+ "Delete Configuration Failed",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }//GEN-LAST:event_deleteConfigurationButtonActionPerformed
+
+ private void runExecutableBrowseButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_runExecutableBrowseButtonActionPerformed
+ {//GEN-HEADEREND:event_runExecutableBrowseButtonActionPerformed
+ JFileChooser chooser = new JFileChooser();
+
+ if (runExecutableTextField.getText().isEmpty()) {
+ chooser.setCurrentDirectory(Paths.get(projectRoot, buildDirectoryTextField.getText()).toFile());
+ }
+ else {
+ chooser.setSelectedFile(Paths.get(projectRoot, runExecutableTextField.getText()).toFile());
+ }
+ chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ chooser.setFileHidingEnabled(false);
+ final int result = chooser.showDialog(this, "Select");
+ if (result == JFileChooser.APPROVE_OPTION) {
+ runExecutableTextField.setText(
+ Paths.get(projectRoot).relativize(chooser.getSelectedFile().toPath()).toString());
+ }
+ }//GEN-LAST:event_runExecutableBrowseButtonActionPerformed
+
+ private void runDirectoryBrowseButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_runDirectoryBrowseButtonActionPerformed
+ {//GEN-HEADEREND:event_runDirectoryBrowseButtonActionPerformed
+ JFileChooser chooser = new JFileChooser();
+ if (runDirectoryTextField.getText().isEmpty()) {
+ chooser.setCurrentDirectory(Paths.get(projectRoot).toFile());
+ }
+ else {
+ chooser.setSelectedFile(Paths.get(projectRoot, runDirectoryTextField.getText()).toFile());
+ }
+ chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ chooser.setFileHidingEnabled(false);
+ final int result = chooser.showDialog(this, "Select");
+ if (result == JFileChooser.APPROVE_OPTION) {
+ runDirectoryTextField.setText(
+ Paths.get(projectRoot).relativize(chooser.getSelectedFile().toPath()).toString());
+ }
+ }//GEN-LAST:event_runDirectoryBrowseButtonActionPerformed
+
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JTable additionalArgumentsTable;
+ private javax.swing.JComboBox<String> backendComboBox;
+ private javax.swing.JLabel backendLabel;
+ private javax.swing.JButton buildDirectoryBrowseButton;
+ private javax.swing.JLabel buildDirectoryLabel;
+ private javax.swing.JTextField buildDirectoryTextField;
+ private javax.swing.JComboBox<String> buildTypeComboBox;
+ private javax.swing.JLabel buildTypeLabel;
+ private javax.swing.JComboBox<String> configurationComboBox;
+ private javax.swing.JLabel configurationLabel;
+ private javax.swing.JButton deleteConfigurationButton;
+ private javax.swing.JScrollPane jScrollPane1;
+ private javax.swing.JSeparator jSeparator1;
+ private javax.swing.JSeparator jSeparator2;
+ private javax.swing.JButton newConfigurationButton;
+ private javax.swing.JButton renameConfigurationButton;
+ private javax.swing.JLabel runArgumentsLabel;
+ private javax.swing.JTextField runArgumentsTextField;
+ private javax.swing.JButton runDirectoryBrowseButton;
+ private javax.swing.JLabel runDirectoryLabel;
+ private javax.swing.JTextField runDirectoryTextField;
+ private javax.swing.JButton runExecutableBrowseButton;
+ private javax.swing.JLabel runExecutableLabel;
+ private javax.swing.JTextField runExecutableTextField;
+ private javax.swing.JComboBox<String> wrapModeComboBox;
+ private javax.swing.JLabel wrapModeLabel;
+ // End of variables declaration//GEN-END:variables
+
+ @ProjectCustomizer.CompositeCategoryProvider.Registration(projectType=MesonProject.PROJECT_KEY, position=220)
+ public static ProjectCustomizer.CompositeCategoryProvider createCategoryProvider() {
+ return new ProjectCustomizer.CompositeCategoryProvider() {
+ @Override
+ public ProjectCustomizer.Category createCategory(Lookup context) {
+ return ProjectCustomizer.Category.create("configuration", "Configuration", null);
+ }
+ @Override
+ public JComponent createComponent(ProjectCustomizer.Category category, Lookup context) {
+ MesonProject project = context.lookup(MesonProject.class);
+ ConfigurationPanel panel = new ConfigurationPanel(project.getProjectDirectory().getPath());
+ panel.load(project.getConfigurationProvider());
+ category.setOkButtonListener(evt -> {
+ panel.commit(project.getConfigurationProvider());
+ });
+ category.setStoreListener(evt -> {
+ project.getConfigurationProvider().save();
+ });
+ return panel;
+ }
+ };
+ }
+
+ private final String projectRoot;
+ private List<Configuration> configurations = new ArrayList<>();
+
+ private final class ConfigurationComboBoxModel implements ComboBoxModel<String> {
+ private String selectedItem = null;
+ private ListDataListener listener = null;
+
+ @Override
+ public void setSelectedItem(Object o) {
+ selectedItem = o.toString();
+ }
+
+ @Override
+ public Object getSelectedItem() {
+ return selectedItem;
+ }
+
+ @Override
+ public int getSize() {
+ return configurations.size();
+ }
+
+ @Override
+ public String getElementAt(int i) {
+ return configurations.get(i).getDisplayName();
+ }
+
+ @Override
+ public void addListDataListener(ListDataListener ll) {
+ listener = ll;
+ }
+
+ @Override
+ public void removeListDataListener(ListDataListener ll) {
+ if (listener == ll) {
+ listener = null;
+ }
+ }
+
+ public void configurationsChanged() {
+ if (selectedItem != null) {
+ boolean found = false;
+ for (Configuration cfg: configurations) {
+ if (selectedItem.equals(cfg.getDisplayName())) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ selectedItem = null;
+ }
+ }
+
+ if (listener != null) {
+ listener.contentsChanged(
+ new ListDataEvent(
+ this,
+ ListDataEvent.CONTENTS_CHANGED,
+ 0,
+ getSize() - 1));
+ }
+
+ if ((selectedItem == null) && !configurations.isEmpty()) {
+ configurationComboBox.setSelectedItem(
+ configurations.get(0).getDisplayName());
+ }
+ }
+ }
+
+ private ConfigurationComboBoxModel configurationComboBoxModel = new ConfigurationComboBoxModel();
+
+ private void load(ConfigurationProvider provider) {
+ for (Configuration cfg: provider.getConfigurations()) {
+ configurations.add(new Configuration(cfg));
+ }
+ configurationComboBoxModel.configurationsChanged();
+ configurationComboBox.setSelectedItem(
+ provider.getActiveConfiguration().getDisplayName());
+ }
+
+ private void commit(ConfigurationProvider provider) {
+ final String selectedCfg = configurationComboBox.getSelectedItem().toString();
+
+ for (Configuration cfg: configurations) {
+ if (selectedCfg.equals(cfg.getDisplayName())) {
+ fromUI(cfg);
+ break;
+ }
+ }
+
+ provider.setConfigurations(configurations);
+ }
+
+ private void toUI(Configuration cfg) {
+ buildDirectoryTextField.setText(cfg.getBuildDirectory());
+ buildTypeComboBox.setSelectedItem(cfg.getBuildType());
+ backendComboBox.setSelectedItem(cfg.getBackend());
+ wrapModeComboBox.setSelectedItem(cfg.getWrapMode());
+ additionalArgumentsTable.setValueAt(cfg.getAdditionalArgumentsFor(COMMAND_SETUP), 0, 1);
+ additionalArgumentsTable.setValueAt(cfg.getAdditionalArgumentsFor(COMMAND_BUILD), 1, 1);
+ additionalArgumentsTable.setValueAt(cfg.getAdditionalArgumentsFor(COMMAND_TEST), 2, 1);
+ runExecutableTextField.setText(cfg.getRunExecutable());
+ runArgumentsTextField.setText(cfg.getRunArguments());
+ runDirectoryTextField.setText(cfg.getRunDirectory());
+ }
+
+ private void fromUI(Configuration cfg) {
+ cfg.setBuildDirectory(buildDirectoryTextField.getText());
+ cfg.setBuildType(buildTypeComboBox.getSelectedItem().toString());
+ cfg.setBackend(backendComboBox.getSelectedItem().toString());
+ cfg.setWrapMode(wrapModeComboBox.getSelectedItem().toString());
+ cfg.setAdditionalArgumentsFor(COMMAND_SETUP, additionalArgumentsTable.getValueAt(0, 1).toString());
+ cfg.setAdditionalArgumentsFor(COMMAND_BUILD, additionalArgumentsTable.getValueAt(1, 1).toString());
+ cfg.setAdditionalArgumentsFor(COMMAND_TEST, additionalArgumentsTable.getValueAt(2, 1).toString());
+ cfg.setRunExecutable(runExecutableTextField.getText());
+ cfg.setRunArguments(runArgumentsTextField.getText());
+ cfg.setRunDirectory(runDirectoryTextField.getText());
+ }
+}
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ui/CustomizerProviderImpl.java b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ui/CustomizerProviderImpl.java
new file mode 100644
index 0000000..b1e9363
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/project/ui/CustomizerProviderImpl.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.meson.project.ui;
+
+import org.netbeans.modules.cnd.meson.project.MesonProject;
+import org.netbeans.spi.project.ui.CustomizerProvider2;
+import org.netbeans.spi.project.ui.support.ProjectCustomizer;
+import org.openide.util.HelpCtx;
+
+public class CustomizerProviderImpl implements CustomizerProvider2 {
+
+ private final MesonProject project;
+
+ public CustomizerProviderImpl(MesonProject project) {
+ this.project = project;
+ }
+
+ @Override
+ public void showCustomizer(String preselectedCategory, String preselectedSubCategory) {
+ ProjectCustomizer.createCustomizerDialog(
+ "Projects/" + MesonProject.PROJECT_KEY + "/Customizer",
+ project.getLookup(),
+ preselectedCategory,
+ evt -> {},
+ HelpCtx.DEFAULT_HELP).setVisible(true);
+ }
+
+ @Override
+ public void showCustomizer() {
+ showCustomizer(null, null);
+ }
+}
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/file_icon.png b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/file_icon.png
new file mode 100644
index 0000000..c73a2cc
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/file_icon.png
Binary files differ
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/fonts_and_colors.xml b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/fonts_and_colors.xml
new file mode 100644
index 0000000..3797679
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/fonts_and_colors.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<!DOCTYPE fontscolors PUBLIC "-//NetBeans//DTD Editor Fonts and Colors settings 1.1//EN" "http://www.netbeans.org/dtds/EditorFontsColors-1_1.dtd">
+<fontscolors>
+ <fontcolor default="error" name="error"/>
+ <fontcolor default="keyword" name="keyword"/>
+ <fontcolor default="whitespace" name="whitespace"/>
+ <fontcolor default="number" name="number"/>
+ <fontcolor default="operator" name="operator"/>
+ <fontcolor default="string" name="string"/>
+ <fontcolor default="keyword" name="command"/>
+ <fontcolor default="comment" name="comment"/>
+ <fontcolor default="identifier" name="identifier"/>
+ <fontcolor default="literal" name="literal"/>
+</fontscolors>
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/layer.xml b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/layer.xml
new file mode 100644
index 0000000..1a85ba9
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/layer.xml
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
+<filesystem>
+ <folder name="Editors">
+ <folder name="text">
+ <folder name="x-meson-build">
+ <file name="language.instance">
+ <attr name="instanceCreate" methodvalue="org.netbeans.modules.cnd.meson.lexer.MesonBuildTokenId.language"/>
+ <attr name="instanceOf" stringvalue="org.netbeans.api.lexer.Language"/>
+ </file>
+ <folder name="FontsColors">
+ <folder name="NetBeans">
+ <folder name="Defaults">
+ <file name="fontsColors.xml" url="fonts_and_colors.xml">
+ <attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.cnd.meson.editor.Bundle"/>
+ </file>
+ </folder>
+ </folder>
+ </folder>
+ <file name="EditorKit.instance">
+ <attr name="instanceClass" stringvalue="org.netbeans.modules.cnd.meson.editor.MesonBuildKit"/>
+ <attr name="instanceOf" stringvalue="javax.swing.text.EditorKit"/>
+ </file>
+ </folder>
+ <folder name="x-meson-options">
+ <file name="language.instance">
+ <attr name="instanceCreate" methodvalue="org.netbeans.modules.cnd.meson.lexer.MesonOptionsTokenId.language"/>
+ <attr name="instanceOf" stringvalue="org.netbeans.api.lexer.Language"/>
+ </file>
+ <folder name="FontsColors">
+ <folder name="NetBeans">
+ <folder name="Defaults">
+ <file name="fontsColors.xml" url="fonts_and_colors.xml">
+ <attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.cnd.meson.editor.Bundle"/>
+ </file>
+ </folder>
+ </folder>
+ </folder>
+ <file name="EditorKit.instance">
+ <attr name="instanceClass" stringvalue="org.netbeans.modules.cnd.meson.editor.MesonOptionsKit"/>
+ <attr name="instanceOf" stringvalue="javax.swing.text.EditorKit"/>
+ </file>
+ </folder>
+ </folder>
+ </folder>
+ <folder name="Projects">
+ <folder name="org-netbeans-modules-cnd-meson-project">
+ <folder name="Actions">
+ <file name="org-netbeans-modules-project-ui-NewFile$WithSubMenu.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-NewFile$WithSubMenu.instance"/>
+ <attr name="position" intvalue="100"/>
+ </file>
+ <file name="sep-1.instance">
+ <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
+ <attr name="position" intvalue="200"/>
+ </file>
+ <file name="org-netbeans-modules-cnd-meson-project-SetupAction.instance">
+ <attr name="instanceCreate" methodvalue="org.netbeans.modules.cnd.meson.project.ActionProviderImpl.createSetupAction"/>
+ <attr name="position" intvalue="250"/>
+ </file>
+ <file name="org-netbeans-modules-project-ui-BuildProject.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-BuildProject.instance"/>
+ <attr name="position" intvalue="300"/>
+ </file>
+ <file name="org-netbeans-modules-project-ui-RebuildProject.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-RebuildProject.instance"/>
+ <attr name="position" intvalue="400"/>
+ </file>
+ <file name="org-netbeans-modules-project-ui-CleanProject.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-CleanProject.instance"/>
+ <attr name="position" intvalue="600"/>
+ </file>
+ <file name="sep-2.instance">
+ <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
+ <attr name="position" intvalue="800"/>
+ </file>
+ <file name="org-netbeans-modules-project-ui-TestProject.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-TestProject.instance"/>
+ <attr name="position" intvalue="850"/>
+ </file>
+ <file name="org-netbeans-modules-project-ui-RunProject.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-RunProject.instance"/>
+ <attr name="position" intvalue="900"/>
+ </file>
+ <file name="org-netbeans-modules-debugger-ui-actions-DebugProjectAction.shadow">
+ <attr name="originalFile" stringvalue="Actions/Debug/org-netbeans-modules-debugger-ui-actions-DebugProjectAction.instance"/>
+ <attr name="position" intvalue="1000"/>
+ </file>
+ <file name="sep-3.instance">
+ <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
+ <attr name="position" intvalue="1300"/>
+ </file>
+ <file name="org-netbeans-modules-project-ui-actions-ActiveConfigAction.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-actions-ActiveConfigAction.instance"/>
+ <attr name="position" intvalue="1500"/>
+ </file>
+ <file name="sep-4.instance">
+ <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
+ <attr name="position" intvalue="1600"/>
+ </file>
+ <file name="org-netbeans-modules-project-ui-SetMainProject.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-SetMainProject.instance"/>
+ <attr name="position" intvalue="1800"/>
+ </file>
+<!-- <file name="org-netbeans-modules-project-ui-actions-OpenSubprojects.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-actions-OpenSubprojects.instance"/>
+ <attr name="position" intvalue="1900"/>
+ </file>-->
+ <file name="org-netbeans-modules-project-ui-CloseProject.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-CloseProject.instance"/>
+ <attr name="position" intvalue="2100"/>
+ </file>
+ <file name="sep-5.instance">
+ <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
+ <attr name="position" intvalue="2200"/>
+ </file>
+ <file name="org-netbeans-modules-project-ui-RenameProject.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-RenameProject.instance"/>
+ <attr name="position" intvalue="2300"/>
+ </file>
+ <file name="org-netbeans-modules-project-ui-MoveProject.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-MoveProject.instance"/>
+ <attr name="position" intvalue="2400"/>
+ </file>
+ <file name="org-netbeans-modules-project-ui-CopyProject.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-CopyProject.instance"/>
+ <attr name="position" intvalue="2500"/>
+ </file>
+ <file name="org-netbeans-modules-project-ui-DeleteProject.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-DeleteProject.instance"/>
+ <attr name="position" intvalue="2600"/>
+ </file>
+ <file name="sep-6.instance">
+ <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
+ <attr name="position" intvalue="2700"/>
+ </file>
+ <file name="org-openide-actions-FindAction.shadow">
+ <attr name="originalFile" stringvalue="Actions/Edit/org-openide-actions-FindAction.instance"/>
+ <attr name="position" intvalue="2800"/>
+ </file>
+ <file name="general.shadow">
+ <attr name="originalFile" stringvalue="Projects/Actions"/>
+ <attr name="position" intvalue="2900"/>
+ </file>
+ <file name="sep-7.instance">
+ <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
+ <attr name="position" intvalue="3000"/>
+ </file>
+ <file name="org-netbeans-modules-project-ui-CustomizeProject.shadow">
+ <attr name="originalFile" stringvalue="Actions/Project/org-netbeans-modules-project-ui-CustomizeProject.instance"/>
+ <attr name="position" intvalue="3200"/>
+ </file>
+ </folder>
+ </folder>
+ </folder>
+
+ <folder name="Templates">
+ <folder name="meson">
+ <attr name="position" intvalue="1350"/>
+ <attr name="displayName" bundlevalue="org.netbeans.modules.cnd.meson.editor.Bundle#Templates_meson" />
+ </folder>
+ </folder>
+</filesystem>
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/meson.build.template b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/meson.build.template
new file mode 100644
index 0000000..a60777c
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/meson.build.template
@@ -0,0 +1,23 @@
+<#--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<#assign licensePrefix = "# ">
+<#include "${project.licensePath}">
+
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/meson.options.template b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/meson.options.template
new file mode 100644
index 0000000..6327eff
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/meson.options.template
@@ -0,0 +1,24 @@
+<#--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<#assign licensePrefix = "# ">
+<#include "${project.licensePath}">
+
+option('', type: '')
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/mime_resolver.xml b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/mime_resolver.xml
new file mode 100644
index 0000000..6c7af27
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/mime_resolver.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<!DOCTYPE MIME-Resolver PUBLIC "-//NetBeans//DTD MIME Resolver 1.0//EN"
+ "http://www.netbeans.org/dtds/mime-resolver-1_0.dtd">
+
+<MIME-resolver>
+ <file>
+ <name name="meson.build" substring="false" ignorecase="false"/>
+ <ext name="build"/>
+ <resolver mime="text/x-meson-build"/>
+ </file>
+ <file>
+ <name name="meson.options" substring="false" ignorecase="false"/>
+ <ext name="options"/>
+ <resolver mime="text/x-meson-options"/>
+ </file>
+ <file>
+ <name name="meson_options.txt" substring="false" ignorecase="false"/>
+ <ext name="txt"/>
+ <resolver mime="text/x-meson-options"/>
+ </file>
+</MIME-resolver>
\ No newline at end of file
diff --git a/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/project_icon.png b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/project_icon.png
new file mode 100644
index 0000000..37a0ea4
--- /dev/null
+++ b/cnd/cnd.meson/src/org/netbeans/modules/cnd/meson/resources/project_icon.png
Binary files differ
diff --git a/cnd/cnd.ui/nbproject/project.xml b/cnd/cnd.ui/nbproject/project.xml
index 8113d4f..11dc124 100644
--- a/cnd/cnd.ui/nbproject/project.xml
+++ b/cnd/cnd.ui/nbproject/project.xml
@@ -403,6 +403,7 @@
<friend>org.netbeans.modules.cnd.make2netbeans</friend>
<friend>org.netbeans.modules.cnd.makeproject</friend>
<friend>org.netbeans.modules.cnd.makeproject.ui</friend>
+ <friend>org.netbeans.modules.cnd.meson</friend>
<friend>org.netbeans.modules.cnd.modeldiscovery</friend>
<friend>org.netbeans.modules.cnd.modelimpl</friend>
<friend>org.netbeans.modules.cnd.modelutil</friend>
diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties
index efc235e..5911caf 100644
--- a/nbbuild/cluster.properties
+++ b/nbbuild/cluster.properties
@@ -1036,6 +1036,7 @@
cnd.makeproject,\
cnd.makeproject.source.bridge,\
cnd.makeproject.ui,\
+ cnd.meson,\
cnd.remote,\
cnd.remote.projectui,\
cnd.remote.ui,\