From c75c4b2d0ea37e2902ffcc4742c329d679633974 Mon Sep 17 00:00:00 2001 From: Filippo Cucchetto Date: Mon, 16 Sep 2019 22:43:27 +0200 Subject: Nim: Add support for the nimble build system Change-Id: Id3bd977f14bc9d2ec3fa92e162238bbff0513de1 Reviewed-by: Leena Miettinen Reviewed-by: hjk --- .../wizards/projects/nimble/binary/binary.nimble | 14 ++ .../wizards/projects/nimble/binary/src/binary.nim | 5 + .../wizards/projects/nimble/hybrid/hybrid.nimble | 15 ++ .../wizards/projects/nimble/hybrid/src/hybrid.nim | 7 + .../nimble/hybrid/src/hybridpkg/submodule.nim | 6 + .../projects/nimble/hybrid/tests/config.nims | 1 + .../wizards/projects/nimble/hybrid/tests/test1.nim | 12 + .../templates/wizards/projects/nimble/icon.png | Bin 0 -> 1448 bytes .../templates/wizards/projects/nimble/icon@2x.png | Bin 0 -> 2255 bytes .../wizards/projects/nimble/library/library.nimble | 13 + .../projects/nimble/library/src/library.nim | 7 + .../nimble/library/src/library/submodule.nim | 12 + .../projects/nimble/library/tests/config.nims | 1 + .../projects/nimble/library/tests/test1.nim | 12 + .../templates/wizards/projects/nimble/wizard.json | 268 +++++++++++++++++++++ src/plugins/nim/CMakeLists.txt | 8 + src/plugins/nim/Nim.json.in | 10 +- src/plugins/nim/nim.pro | 18 ++ src/plugins/nim/nim.qbs | 8 + src/plugins/nim/nimconstants.h | 19 ++ src/plugins/nim/nimplugin.cpp | 22 +- .../nim/project/nimblebuildconfiguration.cpp | 144 +++++++++++ src/plugins/nim/project/nimblebuildconfiguration.h | 72 ++++++ src/plugins/nim/project/nimblebuildstep.cpp | 189 +++++++++++++++ src/plugins/nim/project/nimblebuildstep.h | 70 ++++++ src/plugins/nim/project/nimblebuildstepwidget.cpp | 58 +++++ src/plugins/nim/project/nimblebuildstepwidget.h | 50 ++++ src/plugins/nim/project/nimblebuildstepwidget.ui | 45 ++++ src/plugins/nim/project/nimblebuildsystem.cpp | 149 ++++++++++++ src/plugins/nim/project/nimblebuildsystem.h | 49 ++++ src/plugins/nim/project/nimbleproject.cpp | 112 +++++++++ src/plugins/nim/project/nimbleproject.h | 88 +++++++ src/plugins/nim/project/nimblerunconfiguration.cpp | 110 +++++++++ src/plugins/nim/project/nimblerunconfiguration.h | 61 +++++ src/plugins/nim/project/nimbletaskstep.cpp | 132 ++++++++++ src/plugins/nim/project/nimbletaskstep.h | 75 ++++++ src/plugins/nim/project/nimbletaskstepwidget.cpp | 157 ++++++++++++ src/plugins/nim/project/nimbletaskstepwidget.h | 66 +++++ src/plugins/nim/project/nimbletaskstepwidget.ui | 82 +++++++ src/plugins/nim/project/nimbuildsystem.cpp | 50 ++-- src/plugins/nim/project/nimbuildsystem.h | 4 +- 41 files changed, 2195 insertions(+), 26 deletions(-) create mode 100644 share/qtcreator/templates/wizards/projects/nimble/binary/binary.nimble create mode 100644 share/qtcreator/templates/wizards/projects/nimble/binary/src/binary.nim create mode 100644 share/qtcreator/templates/wizards/projects/nimble/hybrid/hybrid.nimble create mode 100644 share/qtcreator/templates/wizards/projects/nimble/hybrid/src/hybrid.nim create mode 100644 share/qtcreator/templates/wizards/projects/nimble/hybrid/src/hybridpkg/submodule.nim create mode 100644 share/qtcreator/templates/wizards/projects/nimble/hybrid/tests/config.nims create mode 100644 share/qtcreator/templates/wizards/projects/nimble/hybrid/tests/test1.nim create mode 100644 share/qtcreator/templates/wizards/projects/nimble/icon.png create mode 100644 share/qtcreator/templates/wizards/projects/nimble/icon@2x.png create mode 100644 share/qtcreator/templates/wizards/projects/nimble/library/library.nimble create mode 100644 share/qtcreator/templates/wizards/projects/nimble/library/src/library.nim create mode 100644 share/qtcreator/templates/wizards/projects/nimble/library/src/library/submodule.nim create mode 100644 share/qtcreator/templates/wizards/projects/nimble/library/tests/config.nims create mode 100644 share/qtcreator/templates/wizards/projects/nimble/library/tests/test1.nim create mode 100644 share/qtcreator/templates/wizards/projects/nimble/wizard.json create mode 100644 src/plugins/nim/project/nimblebuildconfiguration.cpp create mode 100644 src/plugins/nim/project/nimblebuildconfiguration.h create mode 100644 src/plugins/nim/project/nimblebuildstep.cpp create mode 100644 src/plugins/nim/project/nimblebuildstep.h create mode 100644 src/plugins/nim/project/nimblebuildstepwidget.cpp create mode 100644 src/plugins/nim/project/nimblebuildstepwidget.h create mode 100644 src/plugins/nim/project/nimblebuildstepwidget.ui create mode 100644 src/plugins/nim/project/nimblebuildsystem.cpp create mode 100644 src/plugins/nim/project/nimblebuildsystem.h create mode 100644 src/plugins/nim/project/nimbleproject.cpp create mode 100644 src/plugins/nim/project/nimbleproject.h create mode 100644 src/plugins/nim/project/nimblerunconfiguration.cpp create mode 100644 src/plugins/nim/project/nimblerunconfiguration.h create mode 100644 src/plugins/nim/project/nimbletaskstep.cpp create mode 100644 src/plugins/nim/project/nimbletaskstep.h create mode 100644 src/plugins/nim/project/nimbletaskstepwidget.cpp create mode 100644 src/plugins/nim/project/nimbletaskstepwidget.h create mode 100644 src/plugins/nim/project/nimbletaskstepwidget.ui diff --git a/share/qtcreator/templates/wizards/projects/nimble/binary/binary.nimble b/share/qtcreator/templates/wizards/projects/nimble/binary/binary.nimble new file mode 100644 index 0000000000..0cefc9ee70 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/binary/binary.nimble @@ -0,0 +1,14 @@ +# Package + +backend = "%{ProjectBackend}" +version = "%{ProjectVersion}" +author = "%{ProjectAuthor}" +description = "%{ProjectDescription}" +license = "%{ProjectLicense}" +srcDir = "src" +bin = @["%{ProjectName}"] + + +# Dependencies + +requires "nim >= %{ProjectNimVersion}" diff --git a/share/qtcreator/templates/wizards/projects/nimble/binary/src/binary.nim b/share/qtcreator/templates/wizards/projects/nimble/binary/src/binary.nim new file mode 100644 index 0000000000..862d40c247 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/binary/src/binary.nim @@ -0,0 +1,5 @@ +# This is just an example to get you started. A typical binary package +# uses this file as the main entry point of the application. + +when isMainModule: + echo("Hello, World!") diff --git a/share/qtcreator/templates/wizards/projects/nimble/hybrid/hybrid.nimble b/share/qtcreator/templates/wizards/projects/nimble/hybrid/hybrid.nimble new file mode 100644 index 0000000000..a2604bff21 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/hybrid/hybrid.nimble @@ -0,0 +1,15 @@ +# Package + +backend = "%{ProjectBackend}" +version = "%{ProjectVersion}" +author = "%{ProjectAuthor}" +description = "%{ProjectDescription}" +license = "%{ProjectLicense}" +srcDir = "src" +installExt = @["nim"] +bin = @["%{ProjectName}"] + + +# Dependencies + +requires "nim >= %{ProjectNimVersion}" diff --git a/share/qtcreator/templates/wizards/projects/nimble/hybrid/src/hybrid.nim b/share/qtcreator/templates/wizards/projects/nimble/hybrid/src/hybrid.nim new file mode 100644 index 0000000000..06dbbf298f --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/hybrid/src/hybrid.nim @@ -0,0 +1,7 @@ +# This is just an example to get you started. A typical hybrid package +# uses this file as the main entry point of the application. + +import %{ProjectName}pkg/submodule + +when isMainModule: + echo(getWelcomeMessage()) diff --git a/share/qtcreator/templates/wizards/projects/nimble/hybrid/src/hybridpkg/submodule.nim b/share/qtcreator/templates/wizards/projects/nimble/hybrid/src/hybridpkg/submodule.nim new file mode 100644 index 0000000000..c4185a4c1c --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/hybrid/src/hybridpkg/submodule.nim @@ -0,0 +1,6 @@ +# This is just an example to get you started. Users of your hybrid library will +# import this file by writing ``import %{ProjectName}pkg/submodule``. Feel free to rename or +# remove this file altogether. You may create additional modules alongside +# this file as required. + +proc getWelcomeMessage*(): string = "Hello, World!" diff --git a/share/qtcreator/templates/wizards/projects/nimble/hybrid/tests/config.nims b/share/qtcreator/templates/wizards/projects/nimble/hybrid/tests/config.nims new file mode 100644 index 0000000000..80091ff6c7 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/hybrid/tests/config.nims @@ -0,0 +1 @@ +switch("path", "$projectDir/../src") diff --git a/share/qtcreator/templates/wizards/projects/nimble/hybrid/tests/test1.nim b/share/qtcreator/templates/wizards/projects/nimble/hybrid/tests/test1.nim new file mode 100644 index 0000000000..cabb157e1c --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/hybrid/tests/test1.nim @@ -0,0 +1,12 @@ +# This is just an example to get you started. You may wish to put all of your +# tests into a single file, or separate them into multiple `test1`, `test2` +# etc. files (better names are recommended, just make sure the name starts with +# the letter 't'). +# +# To run these tests, simply execute `nimble test`. + +import unittest + +import %{ProjectName}pkg/submodule +test "correct welcome": + check getWelcomeMessage() == "Hello, World!" diff --git a/share/qtcreator/templates/wizards/projects/nimble/icon.png b/share/qtcreator/templates/wizards/projects/nimble/icon.png new file mode 100644 index 0000000000..d3f8575b26 Binary files /dev/null and b/share/qtcreator/templates/wizards/projects/nimble/icon.png differ diff --git a/share/qtcreator/templates/wizards/projects/nimble/icon@2x.png b/share/qtcreator/templates/wizards/projects/nimble/icon@2x.png new file mode 100644 index 0000000000..bdc8c57055 Binary files /dev/null and b/share/qtcreator/templates/wizards/projects/nimble/icon@2x.png differ diff --git a/share/qtcreator/templates/wizards/projects/nimble/library/library.nimble b/share/qtcreator/templates/wizards/projects/nimble/library/library.nimble new file mode 100644 index 0000000000..c2b324d043 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/library/library.nimble @@ -0,0 +1,13 @@ +# Package + +backend = "%{ProjectBackend}" +version = "%{ProjectVersion}" +author = "%{ProjectAuthor}" +description = "%{ProjectDescription}" +license = "%{ProjectLicense}" +srcDir = "src" + + +# Dependencies + +requires "nim >= %{ProjectNimVersion}" diff --git a/share/qtcreator/templates/wizards/projects/nimble/library/src/library.nim b/share/qtcreator/templates/wizards/projects/nimble/library/src/library.nim new file mode 100644 index 0000000000..4b2a2701f0 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/library/src/library.nim @@ -0,0 +1,7 @@ +# This is just an example to get you started. A typical library package +# exports the main API in this file. Note that you cannot rename this file +# but you can remove it if you wish. + +proc add*(x, y: int): int = + ## Adds two files together. + return x + y diff --git a/share/qtcreator/templates/wizards/projects/nimble/library/src/library/submodule.nim b/share/qtcreator/templates/wizards/projects/nimble/library/src/library/submodule.nim new file mode 100644 index 0000000000..e9aef4611d --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/library/src/library/submodule.nim @@ -0,0 +1,12 @@ +# This is just an example to get you started. Users of your library will +# import this file by writing ``import %{ProjectName}/submodule``. Feel free to rename or +# remove this file altogether. You may create additional modules alongside +# this file as required. + +type + Submodule* = object + name*: string + +proc initSubmodule*(): Submodule = + ## Initialises a new ``Submodule`` object. + Submodule(name: "Anonymous") diff --git a/share/qtcreator/templates/wizards/projects/nimble/library/tests/config.nims b/share/qtcreator/templates/wizards/projects/nimble/library/tests/config.nims new file mode 100644 index 0000000000..80091ff6c7 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/library/tests/config.nims @@ -0,0 +1 @@ +switch("path", "$projectDir/../src") diff --git a/share/qtcreator/templates/wizards/projects/nimble/library/tests/test1.nim b/share/qtcreator/templates/wizards/projects/nimble/library/tests/test1.nim new file mode 100644 index 0000000000..47be596a6a --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/library/tests/test1.nim @@ -0,0 +1,12 @@ +# This is just an example to get you started. You may wish to put all of your +# tests into a single file, or separate them into multiple `test1`, `test2` +# etc. files (better names are recommended, just make sure the name starts with +# the letter 't'). +# +# To run these tests, simply execute `nimble test`. + +import unittest + +import %{ProjectName} +test "can add": + check add(5, 5) == 10 diff --git a/share/qtcreator/templates/wizards/projects/nimble/wizard.json b/share/qtcreator/templates/wizards/projects/nimble/wizard.json new file mode 100644 index 0000000000..bef6ee34ea --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/nimble/wizard.json @@ -0,0 +1,268 @@ +{ + "version":1, + "kind":"project", + "id":"Z.NimbleProject", + "category":"I.Projects", + "trDescription":"Creates a Nim application with Nimble.", + "trDisplayName":"Nimble Application", + "trDisplayCategory":"Non-Qt Project", + "featuresRequired":[ + "ToolChain.Nim.NimToolChain" + ], + "icon":"icon.png", + "enabled":"%{JS: value('Plugins').indexOf('Nim') >= 0 }", + "options":[ + { + "key":"ProjectFile", + "value":"%{NimProjectFile}" + }, + { + "key":"NimProjectFile", + "value":"%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), 'nimble')}" + }, + { + "key":"NimFileName", + "value":"main.nim" + } + ], + "pages":[ + { + "trDisplayName":"Project Location", + "trShortTitle":"Location", + "typeId":"Project" + }, + { + "trDisplayName":"Define Project Configuration", + "trShortTitle":"Configuration", + "typeId":"Fields", + "data":[ + { + "name":"ProjectType", + "trDisplayName":"Type:", + "type":"ComboBox", + "persistenceKey":"ProjectType", + "data":{ + "items":[ + { + "trKey":"Binary", + "value":"Binary" + }, + { + "trKey":"Library", + "value":"Library" + }, + { + "trKey":"Hybrid", + "value":"Hybrid" + } + ] + } + }, + { + "name":"ProjectAuthor", + "trDisplayName":"Author:", + "type":"LineEdit", + "mandatory":true + }, + { + "name":"ProjectDescription", + "trDisplayName":"Description:", + "type":"LineEdit", + "mandatory":true + }, + { + "name":"ProjectVersion", + "trDisplayName":"Version:", + "type":"LineEdit", + "mandatory":true, + "data":{ + "trText":"0.1.0" + } + }, + { + "name":"ProjectLicense", + "trDisplayName":"License:", + "type":"ComboBox", + "persistenceKey":"LicenseType", + "data":{ + "index":0, + "items":[ + { + "trKey":"MIT", + "value":"MIT" + }, + { + "trKey":"GPL-2.0", + "value":"GPL-2.0" + }, + { + "trKey":"Apache-2.0", + "value":"Apache-2.0" + }, + { + "trKey":"ISC", + "value":"ISC" + }, + { + "trKey":"GPL-3.0", + "value":"GPL-3.0" + }, + { + "trKey":"BSD-3-Clause", + "value":"BSD-3-Clause" + }, + { + "trKey":"LGPL-2.1", + "value":"LGPL-2.1" + }, + { + "trKey":"LGPL-3.0", + "value":"LGPL-3.0" + }, + { + "trKey":"EPL-2.0", + "value":"EPL-2.0" + }, + { + "trKey":"Proprietary", + "value":"Proprietary" + }, + { + "trKey":"Other", + "value":"Other" + } + ] + } + }, + { + "name":"ProjectBackend", + "trDisplayName":"Backend:", + "type":"ComboBox", + "persistenceKey":"BackendType", + "data":{ + "index":0, + "items":[ + { + "trKey":"C", + "value":"c" + }, + { + "trKey":"Cpp", + "value":"cpp" + }, + { + "trKey":"Objective C", + "value":"objc" + }, + { + "trKey":"Javascript", + "value":"js" + } + ] + } + }, + { + "name":"ProjectNimVersion", + "trDisplayName":"Min Nim Version:", + "type":"LineEdit", + "mandatory":true, + "data":{ + "trText":"1.0.0" + } + } + ] + }, + { + "trDisplayName":"Kit Selection", + "trShortTitle":"Kits", + "typeId":"Kits", + "enabled":"%{JS: !value('IsSubproject')}", + "data":{ + "projectFilePath":"%{ProjectFile}" + } + }, + { + "trDisplayName":"Project Management", + "trShortTitle":"Summary", + "typeId":"Summary" + } + ], + "generators":[ + { + "typeId":"File", + "data":[ + { + "source":"binary/binary.nimble", + "target":"%{ProjectFile}", + "openAsProject":true, + "condition":"%{JS: value('ProjectType') === 'Binary'}" + }, + { + "source":"binary/src/binary.nim", + "target":"%{ProjectDirectory}/src/%{ProjectName}.nim", + "condition":"%{JS: value('ProjectType') === 'Binary'}", + "openInEditor": true + }, + { + "source":"hybrid/hybrid.nimble", + "target":"%{ProjectFile}", + "openAsProject":true, + "condition":"%{JS: value('ProjectType') === 'Hybrid'}" + }, + { + "source":"hybrid/src/hybrid.nim", + "target":"%{ProjectDirectory}/src/%{ProjectName}.nim", + "condition":"%{JS: value('ProjectType') === 'Hybrid'}", + "openInEditor": true + }, + { + "source":"hybrid/src/hybridpkg/submodule.nim", + "target":"%{ProjectDirectory}/src/%{ProjectName}pkg/submodule.nim", + "condition":"%{JS: value('ProjectType') === 'Hybrid'}" + }, + { + "source":"hybrid/tests/config.nims", + "target":"%{ProjectDirectory}/tests/config.nims", + "condition":"%{JS: value('ProjectType') === 'Hybrid'}" + }, + { + "source":"hybrid/tests/test1.nim", + "target":"%{ProjectDirectory}/tests/test1.nim", + "condition":"%{JS: value('ProjectType') === 'Hybrid'}" + }, + { + "source":"library/library.nimble", + "target":"%{ProjectFile}", + "openAsProject":true, + "condition":"%{JS: value('ProjectType') === 'Library'}" + }, + { + "source":"library/src/library.nim", + "target":"%{ProjectDirectory}/src/%{ProjectName}.nim", + "condition":"%{JS: value('ProjectType') === 'Library'}", + "openInEditor": true + }, + { + "source":"library/src/library/submodule.nim", + "target":"%{ProjectDirectory}/src/%{ProjectName}/submodule.nim", + "condition":"%{JS: value('ProjectType') === 'Library'}" + }, + { + "source":"library/tests/config.nims", + "target":"%{ProjectDirectory}/tests/config.nims", + "condition":"%{JS: value('ProjectType') === 'Library'}" + }, + { + "source":"library/tests/test1.nim", + "target":"%{ProjectDirectory}/tests/test1.nim", + "condition":"%{JS: value('ProjectType') === 'Library'}" + }, + { + "source":"../git.ignore", + "target":"%{ProjectDirectory}/.gitignore", + "condition":"%{JS: !value('IsSubproject') && value('VersionControl') === 'G.Git'}" + } + ] + } + ] +} diff --git a/src/plugins/nim/CMakeLists.txt b/src/plugins/nim/CMakeLists.txt index a26e787578..2601c60288 100644 --- a/src/plugins/nim/CMakeLists.txt +++ b/src/plugins/nim/CMakeLists.txt @@ -8,6 +8,14 @@ add_qtc_plugin(Nim nim.qrc nimconstants.h nimplugin.cpp nimplugin.h + project/nimblebuildstep.h project/nimblebuildstep.cpp + project/nimblebuildstepwidget.h project/nimblebuildstepwidget.cpp project/nimblebuildstepwidget.ui + project/nimbleproject.h project/nimbleproject.cpp + project/nimblerunconfiguration.h project/nimblerunconfiguration.cpp + project/nimbletaskstep.h project/nimbletaskstep.cpp + project/nimbletaskstepwidget.h project/nimbletaskstepwidget.cpp project/nimbletaskstepwidget.ui + project/nimblebuildsystem.h project/nimblebuildsystem.cpp + project/nimblebuildconfiguration.h project/nimblebuildconfiguration.cpp project/nimbuildsystem.cpp project/nimbuildsystem.h project/nimbuildconfiguration.cpp project/nimbuildconfiguration.h project/nimcompilerbuildstep.cpp project/nimcompilerbuildstep.h diff --git a/src/plugins/nim/Nim.json.in b/src/plugins/nim/Nim.json.in index b9e5d8709f..a3d98945c3 100644 --- a/src/plugins/nim/Nim.json.in +++ b/src/plugins/nim/Nim.json.in @@ -30,13 +30,19 @@ \" \", \" \", - \" Nim source file \", + \" Nim source file\", \" \", \" \", + \" \", + \" \", + \" Nimble project file\", + \" \", + \" \", + \" \", \" \", - \" Nim script file \", + \" Nim script file\", \" \", \" \", \"\" diff --git a/src/plugins/nim/nim.pro b/src/plugins/nim/nim.pro index 31b2adb173..46869353fb 100644 --- a/src/plugins/nim/nim.pro +++ b/src/plugins/nim/nim.pro @@ -14,9 +14,17 @@ HEADERS += \ editor/nimcompletionassistprovider.h \ editor/nimhighlighter.h \ editor/nimindenter.h \ + project/nimblebuildconfiguration.h \ + project/nimblebuildstep.h \ + project/nimblebuildstepwidget.h \ + project/nimbleproject.h \ + project/nimblerunconfiguration.h \ + project/nimbletaskstep.h \ + project/nimbletaskstepwidget.h \ tools/nimlexer.h \ tools/sourcecodestream.h \ project/nimbuildsystem.h \ + project/nimblebuildsystem.h \ project/nimproject.h \ project/nimprojectnode.h \ project/nimbuildconfiguration.h \ @@ -45,8 +53,16 @@ SOURCES += \ editor/nimcompletionassistprovider.cpp \ editor/nimhighlighter.cpp \ editor/nimindenter.cpp \ + project/nimblebuildconfiguration.cpp \ + project/nimblebuildstep.cpp \ + project/nimbletaskstep.cpp \ + project/nimblebuildstepwidget.cpp \ + project/nimbleproject.cpp \ + project/nimblerunconfiguration.cpp \ + project/nimbletaskstepwidget.cpp \ tools/nimlexer.cpp \ project/nimbuildsystem.cpp \ + project/nimblebuildsystem.cpp \ project/nimproject.cpp \ project/nimprojectnode.cpp \ project/nimbuildconfiguration.cpp \ @@ -69,6 +85,8 @@ SOURCES += \ suggest/server.cpp FORMS += \ + project/nimblebuildstepwidget.ui \ + project/nimbletaskstepwidget.ui \ project/nimcompilerbuildstepconfigwidget.ui \ settings/nimcodestylepreferenceswidget.ui \ settings/nimtoolssettingswidget.ui diff --git a/src/plugins/nim/nim.qbs b/src/plugins/nim/nim.qbs index 6964993cea..383999f377 100644 --- a/src/plugins/nim/nim.qbs +++ b/src/plugins/nim/nim.qbs @@ -46,6 +46,14 @@ QtcPlugin { "nimrunconfiguration.h", "nimrunconfiguration.cpp", "nimtoolchain.h", "nimtoolchain.cpp", "nimtoolchainfactory.h", "nimtoolchainfactory.cpp", + "nimblebuildstep.h", "nimblebuildstep.cpp", + "nimblebuildstepwidget.h", "nimblebuildstepwidget.cpp", "nimblebuildstepwidget.ui", + "nimbleproject.h", "nimbleproject.cpp", + "nimblerunconfiguration.h", "nimblerunconfiguration.cpp", + "nimbletaskstep.h", "nimbletaskstep.cpp", + "nimbletaskstepwidget.h", "nimbletaskstepwidget.cpp", "nimbletaskstepwidget.ui", + "nimblebuildsystem.h", "nimblebuildsystem.cpp", + "nimblebuildconfiguration.h", "nimblebuildconfiguration.cpp", ] } diff --git a/src/plugins/nim/nimconstants.h b/src/plugins/nim/nimconstants.h index 03f945689a..61b281fbc7 100644 --- a/src/plugins/nim/nimconstants.h +++ b/src/plugins/nim/nimconstants.h @@ -32,6 +32,7 @@ namespace Nim { namespace Constants { const char C_NIMPROJECT_ID[] = "Nim.NimProject"; +const char C_NIMBLEPROJECT_ID[] = "Nim.NimbleProject"; const char C_NIMEDITOR_ID[] = "Nim.NimEditor"; const char C_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "Nim Editor"); @@ -39,11 +40,28 @@ const char C_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "Nim const char C_NIMTOOLCHAIN_TYPEID[] = "Nim.NimToolChain"; const char C_NIMTOOLCHAIN_COMPILER_COMMAND_KEY[] = "Nim.NimToolChain.CompilerCommand"; +// NimbleProject +const char C_NIMBLEPROJECT_TASKS[] = "Nim.NimbleProject.Tasks"; +const char C_NIMBLEPROJECT_METADATA[] = "Nim.NimbleProject.Metadata"; + // NimProject const char C_NIMPROJECT_EXCLUDEDFILES[] = "Nim.NimProjectExcludedFiles"; // NimBuildConfiguration const char C_NIMBUILDCONFIGURATION_ID[] = "Nim.NimBuildConfiguration"; +const char C_NIMBLEBUILDCONFIGURATION_ID[] = "Nim.NimbleBuildConfiguration"; +const char C_NIMBLEBUILDCONFIGURATION_BUILDTYPE[] = "Nim.NimbleBuildConfiguration.BuildType"; + +// NimbleBuildStep +const char C_NIMBLEBUILDSTEP_ID[] = "Nim.NimbleBuildStep"; +const char C_NIMBLEBUILDSTEP_DISPLAY[] = QT_TRANSLATE_NOOP("NimbleBuildStep", "Nimble Build"); +const char C_NIMBLEBUILDSTEP_ARGUMENTS[] = "Nim.NimbleBuildStep.Arguments"; + +// NimbleTaskStep +const char C_NIMBLETASKSTEP_ID[] = "Nim.NimbleTaskStep"; +const char C_NIMBLETASKSTEP_DISPLAY[] = QT_TRANSLATE_NOOP("NimbleTaskStep", "Nimble Task"); +const QString C_NIMBLETASKSTEP_TASKNAME = QStringLiteral("Nim.NimbleTaskStep.TaskName"); +const QString C_NIMBLETASKSTEP_TASKARGS = QStringLiteral("Nim.NimbleTaskStep.TaskArgs"); // NimCompilerBuildStep const char C_NIMCOMPILERBUILDSTEP_ID[] = "Nim.NimCompilerBuildStep"; @@ -92,6 +110,7 @@ const char C_NIMCODESTYLEPREVIEWSNIPPET[] = * MIME type ******************************************************************************/ const char C_NIM_MIMETYPE[] = "text/x-nim"; +const char C_NIMBLE_MIMETYPE[] = "text/x-nimble"; const char C_NIM_SCRIPT_MIMETYPE[] = "text/x-nim-script"; const char C_NIM_MIME_ICON[] = "text-x-nim"; const char C_NIM_PROJECT_MIMETYPE[] = "text/x-nim-project"; diff --git a/src/plugins/nim/nimplugin.cpp b/src/plugins/nim/nimplugin.cpp index 7740e6096e..152249d4ee 100644 --- a/src/plugins/nim/nimplugin.cpp +++ b/src/plugins/nim/nimplugin.cpp @@ -28,12 +28,17 @@ #include "nimconstants.h" #include "editor/nimeditorfactory.h" #include "editor/nimhighlighter.h" +#include "project/nimblerunconfiguration.h" +#include "project/nimblebuildconfiguration.h" #include "project/nimbuildconfiguration.h" #include "project/nimcompilerbuildstep.h" #include "project/nimcompilercleanstep.h" #include "project/nimproject.h" +#include "project/nimbleproject.h" #include "project/nimrunconfiguration.h" #include "project/nimtoolchainfactory.h" +#include "project/nimblebuildstep.h" +#include "project/nimbletaskstep.h" #include "settings/nimcodestylepreferencesfactory.h" #include "settings/nimcodestylesettingspage.h" #include "settings/nimtoolssettingspage.h" @@ -66,12 +71,21 @@ public: NimSettings settings; NimEditorFactory editorFactory; NimBuildConfigurationFactory buildConfigFactory; - NimRunConfigurationFactory runConfigFactory; - RunWorkerFactory runWorkerFactory{ + NimbleBuildConfigurationFactory nimbleBuildConfigFactory; + NimRunConfigurationFactory nimRunConfigFactory; + NimbleRunConfigurationFactory nimbleRunConfigFactory; + RunWorkerFactory nimRunWorkerFactory { RunWorkerFactory::make(), {ProjectExplorer::Constants::NORMAL_RUN_MODE}, - {runConfigFactory.id()} + {nimRunConfigFactory.id()} }; + RunWorkerFactory nimbleRunWorkerFactory { + RunWorkerFactory::make(), + {ProjectExplorer::Constants::NORMAL_RUN_MODE}, + {nimbleRunConfigFactory.id()} + }; + NimbleBuildStepFactory nimbleBuildStepFactory; + NimbleTaskStepFactory nimbleTaskStepFactory; NimCompilerBuildStepFactory buildStepFactory; NimCompilerCleanStepFactory cleanStepFactory; NimCodeStyleSettingsPage codeStyleSettingsPage; @@ -99,6 +113,7 @@ bool NimPlugin::initialize(const QStringList &arguments, QString *errorMessage) &NimEditorFactory::decorateEditor); ProjectManager::registerProjectType(Constants::C_NIM_PROJECT_MIMETYPE); + ProjectManager::registerProjectType(Constants::C_NIMBLE_MIMETYPE); return true; } @@ -112,6 +127,7 @@ void NimPlugin::extensionsInitialized() if (!icon.isNull()) { Core::FileIconProvider::registerIconOverlayForMimeType(icon, Constants::C_NIM_MIMETYPE); Core::FileIconProvider::registerIconOverlayForMimeType(icon, Constants::C_NIM_SCRIPT_MIMETYPE); + Core::FileIconProvider::registerIconOverlayForMimeType(icon, Constants::C_NIMBLE_MIMETYPE); } } diff --git a/src/plugins/nim/project/nimblebuildconfiguration.cpp b/src/plugins/nim/project/nimblebuildconfiguration.cpp new file mode 100644 index 0000000000..8b947ce3cc --- /dev/null +++ b/src/plugins/nim/project/nimblebuildconfiguration.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "nimblebuildconfiguration.h" +#include "nimconstants.h" +#include "nimblebuildstep.h" +#include "nimbleproject.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace Nim; +using namespace ProjectExplorer; +using namespace Utils; + +NimbleBuildConfiguration::NimbleBuildConfiguration(Target *target, Core::Id id) + : BuildConfiguration(target, id) +{ + setConfigWidgetDisplayName(tr("General")); + setConfigWidgetHasFrame(true); + setBuildDirectorySettingsKey("Nim.NimbleBuildConfiguration.BuildDirectory"); + + m_nimbleProject = dynamic_cast(project()); + QTC_ASSERT(m_nimbleProject, return); + QObject::connect(m_nimbleProject, &NimbleProject::metadataChanged, this, &NimbleBuildConfiguration::updateApplicationTargets); + updateApplicationTargets(); +} + +BuildConfiguration::BuildType NimbleBuildConfiguration::buildType() const +{ + return m_buildType; +} + +void NimbleBuildConfiguration::initialize() +{ + BuildConfiguration::initialize(); + + m_buildType = initialBuildType(); + + setBuildDirectory(project()->projectDirectory()); + + // Don't add a nimble build step when the package has no binaries (i.e a library package) + if (!m_nimbleProject->metadata().bin.empty()) + { + BuildStepList *buildSteps = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); + buildSteps->appendStep(new NimbleBuildStep(buildSteps)); + } +} + +void NimbleBuildConfiguration::updateApplicationTargets() +{ + QTC_ASSERT(m_nimbleProject, return); + + const NimbleMetadata &metaData = m_nimbleProject->metadata(); + const FilePath &projectDir = project()->projectDirectory(); + const FilePath binDir = projectDir.pathAppended(metaData.binDir); + const FilePath srcDir = projectDir.pathAppended("src"); + + QList targets = Utils::transform(metaData.bin, [&](const QString &bin){ + BuildTargetInfo info = {}; + info.displayName = bin; + info.targetFilePath = binDir.pathAppended(HostOsInfo::withExecutableSuffix(bin)); + info.projectFilePath = srcDir.pathAppended(bin).stringAppended(".nim"); + info.workingDirectory = binDir; + info.buildKey = bin; + return info; + }); + + target()->setApplicationTargets(std::move(targets)); +} + +bool NimbleBuildConfiguration::fromMap(const QVariantMap &map) +{ + m_buildType = static_cast(map[Constants::C_NIMBLEBUILDCONFIGURATION_BUILDTYPE].toInt()); + return BuildConfiguration::fromMap(map); +} + +QVariantMap NimbleBuildConfiguration::toMap() const +{ + auto map = BuildConfiguration::toMap(); + map[Constants::C_NIMBLEBUILDCONFIGURATION_BUILDTYPE] = buildType(); + return map; +} + + +NimbleBuildConfigurationFactory::NimbleBuildConfigurationFactory() +{ + registerBuildConfiguration(Constants::C_NIMBLEBUILDCONFIGURATION_ID); + setSupportedProjectType(Constants::C_NIMBLEPROJECT_ID); + setSupportedProjectMimeTypeName(Constants::C_NIMBLE_MIMETYPE); +} + +QList NimbleBuildConfigurationFactory::availableBuilds(const Kit *k, const Utils::FilePath &projectPath, bool forSetup) const +{ + static const QList configurations = {BuildConfiguration::Debug, BuildConfiguration::Release}; + return Utils::transform(configurations, [&](BuildConfiguration::BuildType buildType){ + BuildInfo info(this); + info.buildType = buildType; + info.kitId = k->id(); + + if (buildType == BuildConfiguration::Debug) + info.typeName = tr("Debug"); + else if (buildType == BuildConfiguration::Release) + info.typeName = tr("Release"); + + if (forSetup) { + info.displayName = info.typeName; + info.buildDirectory = projectPath.parentDir(); + } + return info; + }); +} diff --git a/src/plugins/nim/project/nimblebuildconfiguration.h b/src/plugins/nim/project/nimblebuildconfiguration.h new file mode 100644 index 0000000000..5ba6b5c218 --- /dev/null +++ b/src/plugins/nim/project/nimblebuildconfiguration.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include + +namespace Nim { + +class NimbleProject; + +class NimbleBuildConfiguration : public ProjectExplorer::BuildConfiguration +{ + Q_OBJECT + + friend class ProjectExplorer::BuildConfigurationFactory; + + NimbleBuildConfiguration(ProjectExplorer::Target *target, Core::Id id); + + BuildType buildType() const override; + + bool fromMap(const QVariantMap &map) override; + + QVariantMap toMap() const override; + +protected: + void initialize() override; + + void updateApplicationTargets(); + +private: + NimbleProject *m_nimbleProject = nullptr; + BuildType m_buildType; +}; + +class NimbleBuildConfigurationFactory : public ProjectExplorer::BuildConfigurationFactory +{ + Q_OBJECT + +public: + NimbleBuildConfigurationFactory(); + +private: + QList availableBuilds(const ProjectExplorer::Kit *k, + const Utils::FilePath &projectPath, + bool forSetup) const override; +}; + +} diff --git a/src/plugins/nim/project/nimblebuildstep.cpp b/src/plugins/nim/project/nimblebuildstep.cpp new file mode 100644 index 0000000000..940c3e91eb --- /dev/null +++ b/src/plugins/nim/project/nimblebuildstep.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "nimblebuildstep.h" +#include "nimblebuildstepwidget.h" +#include "nimbletaskstepwidget.h" +#include "nimconstants.h" +#include "nimbleproject.h" + +#include +#include +#include +#include + +#include +#include + +using namespace Nim; +using namespace ProjectExplorer; +using namespace Utils; + +namespace { + +class NimParser : public IOutputParser +{ +public: + void stdOutput(const QString &line) final + { + parseLine(line.trimmed()); + IOutputParser::stdOutput(line); + } + + void stdError(const QString &line) final + { + parseLine(line.trimmed()); + IOutputParser::stdError(line); + } + +private: + void parseLine(const QString &line) + { + static QRegularExpression regex("(.+.nim)\\((\\d+), (\\d+)\\) (.+)", + QRegularExpression::OptimizeOnFirstUsageOption); + static QRegularExpression warning("(Warning):(.*)", + QRegularExpression::OptimizeOnFirstUsageOption); + static QRegularExpression error("(Error):(.*)", + QRegularExpression::OptimizeOnFirstUsageOption); + + QRegularExpressionMatch match = regex.match(line); + if (!match.hasMatch()) + return; + const QString filename = match.captured(1); + bool lineOk = false; + const int lineNumber = match.captured(2).toInt(&lineOk); + const QString message = match.captured(4); + if (!lineOk) + return; + + Task::TaskType type = Task::Unknown; + + if (warning.match(message).hasMatch()) + type = Task::Warning; + else if (error.match(message).hasMatch()) + type = Task::Error; + else + return; + + Task task(type, + message, + Utils::FilePath::fromUserInput(filename), + lineNumber, + ProjectExplorer::Constants::TASK_CATEGORY_COMPILE); + emit addTask(task); + } +}; + +} + +NimbleBuildStep::NimbleBuildStep(BuildStepList *parentList) + : AbstractProcessStep(parentList, Constants::C_NIMBLEBUILDSTEP_ID) +{ + setDefaultDisplayName(tr(Constants::C_NIMBLEBUILDSTEP_DISPLAY)); + setDisplayName(tr(Constants::C_NIMBLEBUILDSTEP_DISPLAY)); + QTC_ASSERT(buildConfiguration(), return); + QObject::connect(buildConfiguration(), &BuildConfiguration::buildTypeChanged, this, &NimbleBuildStep::resetArguments); + QObject::connect(this, &NimbleBuildStep::argumentsChanged, this, &NimbleBuildStep::onArgumentsChanged); + resetArguments(); +} + +bool NimbleBuildStep::init() +{ + auto parser = new NimParser(); + parser->setWorkingDirectory(project()->projectDirectory()); + setOutputParser(parser); + + ProcessParameters* params = processParameters(); + params->setEnvironment(buildConfiguration()->environment()); + params->setMacroExpander(buildConfiguration()->macroExpander()); + params->setWorkingDirectory(project()->projectDirectory()); + params->setCommandLine({QStandardPaths::findExecutable("nimble"), {"build", m_arguments}}); + return AbstractProcessStep::init(); +} + +BuildStepConfigWidget *NimbleBuildStep::createConfigWidget() +{ + return new NimbleBuildStepWidget(this); +} + +QString NimbleBuildStep::arguments() const +{ + return m_arguments; +} + +void NimbleBuildStep::setArguments(const QString &args) +{ + if (m_arguments == args) + return; + m_arguments = args; + emit argumentsChanged(args); +} + +void NimbleBuildStep::resetArguments() +{ + setArguments(defaultArguments()); +} + +bool NimbleBuildStep::fromMap(const QVariantMap &map) +{ + m_arguments = map.value(Constants::C_NIMBLEBUILDSTEP_ARGUMENTS, defaultArguments()).toString(); + return AbstractProcessStep::fromMap(map); +} + +QVariantMap NimbleBuildStep::toMap() const +{ + auto map = AbstractProcessStep::toMap(); + map[Constants::C_NIMBLEBUILDSTEP_ARGUMENTS] = m_arguments; + return map; +} + +QString NimbleBuildStep::defaultArguments() const +{ + QTC_ASSERT(buildConfiguration(), return {}; ); + switch (buildConfiguration()->buildType()) { + case ProjectExplorer::BuildConfiguration::Debug: + return "--debugger:native"; + case ProjectExplorer::BuildConfiguration::Unknown: + case ProjectExplorer::BuildConfiguration::Profile: + case ProjectExplorer::BuildConfiguration::Release: + default: + return ""; + } +} + +void NimbleBuildStep::onArgumentsChanged() +{ + ProcessParameters* params = processParameters(); + params->setCommandLine({QStandardPaths::findExecutable("nimble"), {"build", m_arguments}}); +} + +NimbleBuildStepFactory::NimbleBuildStepFactory() +{ + registerStep(Constants::C_NIMBLEBUILDSTEP_ID); + setDisplayName(NimbleBuildStep::tr("Nimble Build")); + setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); + setSupportedConfiguration(Constants::C_NIMBLEBUILDCONFIGURATION_ID); + setRepeatable(true); +} diff --git a/src/plugins/nim/project/nimblebuildstep.h b/src/plugins/nim/project/nimblebuildstep.h new file mode 100644 index 0000000000..e8bcc18253 --- /dev/null +++ b/src/plugins/nim/project/nimblebuildstep.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace Nim { + +class NimbleBuildStep : public ProjectExplorer::AbstractProcessStep +{ + Q_OBJECT + +public: + NimbleBuildStep(ProjectExplorer::BuildStepList *parentList); + + bool init() override; + + ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override; + + QString arguments() const; + + void setArguments(const QString &args); + + void resetArguments(); + + bool fromMap(const QVariantMap &map) override; + + QVariantMap toMap() const override; + +signals: + void argumentsChanged(const QString &args); + +private: + QString defaultArguments() const; + + void onArgumentsChanged(); + + QString m_arguments; +}; + +class NimbleBuildStepFactory : public ProjectExplorer::BuildStepFactory +{ +public: + NimbleBuildStepFactory(); +}; + +} diff --git a/src/plugins/nim/project/nimblebuildstepwidget.cpp b/src/plugins/nim/project/nimblebuildstepwidget.cpp new file mode 100644 index 0000000000..ad841a4730 --- /dev/null +++ b/src/plugins/nim/project/nimblebuildstepwidget.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "nimblebuildstepwidget.h" +#include "ui_nimblebuildstepwidget.h" + +#include "nimblebuildstep.h" +#include "nimbleproject.h" + +#include + +#include +#include + + +using namespace Nim; +using namespace ProjectExplorer; + +NimbleBuildStepWidget::NimbleBuildStepWidget(NimbleBuildStep *bs) + : BuildStepConfigWidget(bs) + , ui(new Ui::NimbleBuildStepWidget) +{ + ui->setupUi(this); + + ui->argumentsLineEdit->setText(bs->arguments()); + QObject::connect(bs, &NimbleBuildStep::argumentsChanged, ui->argumentsLineEdit, &QLineEdit::setText); + QObject::connect(ui->argumentsLineEdit, &QLineEdit::textEdited, bs, &NimbleBuildStep::setArguments); + + ui->resetButton->setIcon(Utils::Icons::RESET.icon()); + QObject::connect(ui->resetButton, &QToolButton::triggered, bs, &NimbleBuildStep::resetArguments); +} + +NimbleBuildStepWidget::~NimbleBuildStepWidget() +{ + delete ui; +} diff --git a/src/plugins/nim/project/nimblebuildstepwidget.h b/src/plugins/nim/project/nimblebuildstepwidget.h new file mode 100644 index 0000000000..b367e8319f --- /dev/null +++ b/src/plugins/nim/project/nimblebuildstepwidget.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include + +namespace Nim { + +class NimbleBuildStep; + +namespace Ui { class NimbleBuildStepWidget; } + +class NimbleBuildStepWidget : public ProjectExplorer::BuildStepConfigWidget +{ + Q_OBJECT + +public: + explicit NimbleBuildStepWidget(NimbleBuildStep *bs); + + ~NimbleBuildStepWidget(); + +private: + Ui::NimbleBuildStepWidget *ui; +}; + +} diff --git a/src/plugins/nim/project/nimblebuildstepwidget.ui b/src/plugins/nim/project/nimblebuildstepwidget.ui new file mode 100644 index 0000000000..919fdb104b --- /dev/null +++ b/src/plugins/nim/project/nimblebuildstepwidget.ui @@ -0,0 +1,45 @@ + + + Nim::NimbleBuildStepWidget + + + + 0 + 0 + 400 + 50 + + + + Form + + + + + + + + Arguments: + + + + + + + + + + Reset to Default + + + + + + + + + + + + + diff --git a/src/plugins/nim/project/nimblebuildsystem.cpp b/src/plugins/nim/project/nimblebuildsystem.cpp new file mode 100644 index 0000000000..c8d0e81d9a --- /dev/null +++ b/src/plugins/nim/project/nimblebuildsystem.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "nimblebuildsystem.h" +#include "nimbleproject.h" + +#include +#include + +#include +#include + +using namespace Nim; +using namespace ProjectExplorer; +using namespace Utils; + +namespace { + +std::vector parseTasks(const QString &nimblePath, const QString &workingDirectory) +{ + QProcess process; + process.setWorkingDirectory(workingDirectory); + process.start(QStandardPaths::findExecutable(nimblePath), {"tasks"}); + process.waitForFinished(); + + std::vector result; + + QList lines = process.readAllStandardOutput().split('\n'); + lines = Utils::transform(lines, [](const QByteArray &line){ return line.trimmed(); }); + Utils::erase(lines, [](const QByteArray &line) { return line.isEmpty(); }); + + for (const QByteArray &line : lines) { + QList tokens = line.trimmed().split(' '); + QTC_ASSERT(!tokens.empty(), continue); + QString taskName = QString::fromUtf8(tokens.takeFirst()); + QString taskDesc = QString::fromUtf8(tokens.join(' ')); + result.push_back({std::move(taskName), std::move(taskDesc)}); + } + + return result; +} + +NimbleMetadata parseMetadata(const QString &nimblePath, const QString &workingDirectory) { + QProcess process; + process.setWorkingDirectory(workingDirectory); + process.start(QStandardPaths::findExecutable(nimblePath), {"dump"}); + process.waitForFinished(); + + NimbleMetadata result = {}; + + QList lines = process.readAllStandardOutput().split('\n'); + lines = Utils::transform(lines, [](const QByteArray &line){ return line.trimmed(); }); + Utils::erase(lines, [](const QByteArray &line) { return line.isEmpty(); }); + + for (const QByteArray &line : lines) { + QList tokens = line.trimmed().split(':'); + QTC_ASSERT(tokens.size() == 2, continue); + QString name = QString::fromUtf8(tokens.takeFirst()).trimmed(); + QString value = QString::fromUtf8(tokens.takeFirst()).trimmed(); + QTC_ASSERT(value.size() >= 2, continue); + QTC_ASSERT(value.front() == QChar('"'), continue); + QTC_ASSERT(value.back() == QChar('"'), continue); + value.remove(0, 1); + value.remove(value.size() - 1, 1); + + if (name == "binDir") + result.binDir = value; + else if (name == "srcDir") + result.srcDir = value; + else if (name == "bin") { + QStringList bin = value.split(','); + bin = Utils::transform(bin, [](const QString &x){ return x.trimmed(); }); + Utils::erase(bin, [](const QString &x) { return x.isEmpty(); }); + result.bin = std::move(bin); + } + } + + return result; +} + +} + +NimbleBuildSystem::NimbleBuildSystem(Project *project) + : NimBuildSystem(project) +{ +} + +void NimbleBuildSystem::parseProject(BuildSystem::ParsingContext &&ctx) +{ + NimBuildSystem::parseProject(std::move(ctx)); +} + +void NimbleBuildSystem::updateProject() +{ + updateProjectMetaData(); + updateProjectTasks(); +} + +void NimbleBuildSystem::init() +{ + // Not called in parseProject due to nimble behavior to create temporary + // files in project directory. This creation in turn stimulate the fs watcher + // that in turn causes project parsing (thus a loop if invoke in parseProject). + // For this reason we call this function manually during project creation + // See https://github.com/nim-lang/nimble/issues/720 + m_directoryWatcher.addFile(project()->projectFilePath().toString(), FileSystemWatcher::WatchModifiedDate); + connect(&m_directoryWatcher, &FileSystemWatcher::fileChanged, this, [this](const QString &path) { + if (path == project()->projectFilePath().toString()) { + updateProject(); + } + }); + updateProject(); +} + +void NimbleBuildSystem::updateProjectTasks() +{ + auto prj = dynamic_cast(project()); + QTC_ASSERT(prj, return); + prj->setTasks(parseTasks(QStandardPaths::findExecutable("nimble"), project()->projectDirectory().toString())); +} + +void NimbleBuildSystem::updateProjectMetaData() +{ + auto prj = dynamic_cast(project()); + QTC_ASSERT(prj, return); + prj->setMetadata(parseMetadata(QStandardPaths::findExecutable("nimble"), project()->projectDirectory().toString())); +} diff --git a/src/plugins/nim/project/nimblebuildsystem.h b/src/plugins/nim/project/nimblebuildsystem.h new file mode 100644 index 0000000000..4ffd9185e7 --- /dev/null +++ b/src/plugins/nim/project/nimblebuildsystem.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace Nim { + +class NimbleBuildSystem : public NimBuildSystem +{ + Q_OBJECT + +public: + NimbleBuildSystem(ProjectExplorer::Project *project); + + void init(); + +protected: + void parseProject(ParsingContext &&ctx) override; + + void updateProject(); + void updateProjectTasks(); + void updateProjectMetaData(); +}; + +} diff --git a/src/plugins/nim/project/nimbleproject.cpp b/src/plugins/nim/project/nimbleproject.cpp new file mode 100644 index 0000000000..067c647e97 --- /dev/null +++ b/src/plugins/nim/project/nimbleproject.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "nimbleproject.h" +#include "nimconstants.h" +#include "nimblebuildsystem.h" + +#include +#include +#include + +using namespace Nim; +using namespace ProjectExplorer; + +NimbleProject::NimbleProject(const Utils::FilePath &fileName) + : ProjectExplorer::Project(Constants::C_NIMBLE_MIMETYPE, fileName) +{ + setId(Constants::C_NIMBLEPROJECT_ID); + setDisplayName(fileName.toFileInfo().completeBaseName()); + // ensure debugging is enabled (Nim plugin translates nim code to C code) + setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); + auto bs = std::make_unique(this); + bs->init(); + setBuildSystem(std::move(bs)); +} + +std::vector NimbleProject::tasks() const +{ + return m_tasks; +} + +NimbleMetadata NimbleProject::metadata() const +{ + return m_metadata; +} + +void NimbleProject::setTasks(std::vector tasks) +{ + if (tasks == m_tasks) + return; + m_tasks = std::move(tasks); + emit tasksChanged(m_tasks); +} + +void NimbleProject::setMetadata(NimbleMetadata metadata) +{ + if (m_metadata == metadata) + return; + m_metadata = std::move(metadata); + emit metadataChanged(m_metadata); +} + +QVariantMap NimbleProject::toMap() const +{ + QVariantMap result = Project::toMap(); + result[Constants::C_NIMPROJECT_EXCLUDEDFILES] = static_cast(buildSystem()) + ->excludedFiles(); + result[Constants::C_NIMBLEPROJECT_TASKS] = toStringList(m_tasks); + return result; +} + +Project::RestoreResult NimbleProject::fromMap(const QVariantMap &map, QString *errorMessage) +{ + static_cast(buildSystem()) + ->setExcludedFiles(map.value(Constants::C_NIMPROJECT_EXCLUDEDFILES).toStringList()); + Project::RestoreResult result = Project::RestoreResult::Error; + std::tie(result, m_tasks) = fromStringList(map.value(Constants::C_NIMBLEPROJECT_TASKS).toStringList()); + return result == Project::RestoreResult::Ok ? Project::fromMap(map, errorMessage) : result; +} + +QStringList NimbleProject::toStringList(const std::vector &tasks) +{ + QStringList result; + for (const NimbleTask &task : tasks) { + result.push_back(task.name); + result.push_back(task.description); + } + return result; +} + +std::tuple> NimbleProject::fromStringList(const QStringList &list) +{ + if (list.size() % 2 != 0) + return {Project::RestoreResult::Error, {}}; + + std::vector result; + for (int i = 0; i < list.size(); i += 2) + result.push_back({list[i], list[i + 1]}); + return {Project::RestoreResult::Ok, std::move(result)}; +} diff --git a/src/plugins/nim/project/nimbleproject.h b/src/plugins/nim/project/nimbleproject.h new file mode 100644 index 0000000000..e3c7cf9358 --- /dev/null +++ b/src/plugins/nim/project/nimbleproject.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace Nim { + +struct NimbleTask +{ + QString name; + QString description; + + bool operator==(const NimbleTask &o) const { + return name == o.name && description == o.description; + } +}; + +struct NimbleMetadata +{ + QStringList bin; + QString binDir; + QString srcDir; + + bool operator==(const NimbleMetadata &o) const { + return bin == o.bin && binDir == o.binDir && srcDir == o.srcDir; + } +}; + +class NimbleProject : public ProjectExplorer::Project +{ + Q_OBJECT + +public: + NimbleProject(const Utils::FilePath &filename); + + std::vector tasks() const; + + NimbleMetadata metadata() const; + + void setTasks(std::vector tasks); + + void setMetadata(NimbleMetadata metadata); + + // Keep for compatibility with Qt Creator 4.10 + QVariantMap toMap() const final; + +signals: + void tasksChanged(std::vector); + void metadataChanged(NimbleMetadata); + +protected: + // Keep for compatibility with Qt Creator 4.10 + RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final; + +private: + static QStringList toStringList(const std::vector &tasks); + + static std::tuple> fromStringList(const QStringList &list); + + NimbleMetadata m_metadata; + std::vector m_tasks; +}; + +} diff --git a/src/plugins/nim/project/nimblerunconfiguration.cpp b/src/plugins/nim/project/nimblerunconfiguration.cpp new file mode 100644 index 0000000000..4e4748ebd8 --- /dev/null +++ b/src/plugins/nim/project/nimblerunconfiguration.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "nimblerunconfiguration.h" +#include "nimconstants.h" +#include "nimbleproject.h" + +#include +#include +#include +#include + +#include +#include + +using namespace Nim; +using namespace ProjectExplorer; + +NimbleRunConfiguration::NimbleRunConfiguration(ProjectExplorer::Target *target, Core::Id id) + : RunConfiguration(target, id) +{ + auto project = dynamic_cast(target->project()); + QTC_ASSERT(project, return); + + addAspect(target); + addAspect(); + addAspect(); + addAspect(); + addAspect(); + + connect(project, &Project::parsingFinished, + this, &NimbleRunConfiguration::updateTargetInformation); + connect(project, &NimbleProject::metadataChanged, + this, &NimbleRunConfiguration::updateTargetInformation); + connect(project, &NimbleProject::tasksChanged, + this, &NimbleRunConfiguration::updateTargetInformation); + + updateTargetInformation(); +} + +NimbleRunConfiguration::~NimbleRunConfiguration() +{ + +} + +void NimbleRunConfiguration::updateTargetInformation() +{ + BuildTargetInfo bti = buildTargetInfo(); + setDisplayName(bti.displayName); + setDefaultDisplayName(bti.displayName); + aspect()->setExecutable(bti.targetFilePath); + aspect()->setDefaultWorkingDirectory(bti.workingDirectory); +} + +bool NimbleRunConfiguration::isBuildTargetValid() const +{ + return Utils::anyOf(target()->applicationTargets(), [this](const BuildTargetInfo &bti) { + return bti.buildKey == buildKey(); + }); +} + +QString NimbleRunConfiguration::disabledReason() const +{ + if (!isBuildTargetValid()) + return tr("The project no longer builds the target associated with this run configuration."); + return RunConfiguration::disabledReason(); +} + +void NimbleRunConfiguration::updateEnabledState() +{ + if (!isBuildTargetValid()) + setEnabled(false); + else + RunConfiguration::updateEnabledState(); +} + +NimbleRunConfigurationFactory::NimbleRunConfigurationFactory() + : RunConfigurationFactory() +{ + registerRunConfiguration("Nim.NimbleRunConfiguration"); + addSupportedProjectType(Constants::C_NIMBLEPROJECT_ID); + addSupportedTargetDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE); +} + +QList NimbleRunConfigurationFactory::availableCreators(Target *parent) const +{ + return RunConfigurationFactory::availableCreators(parent); +} diff --git a/src/plugins/nim/project/nimblerunconfiguration.h b/src/plugins/nim/project/nimblerunconfiguration.h new file mode 100644 index 0000000000..b273fd4f2b --- /dev/null +++ b/src/plugins/nim/project/nimblerunconfiguration.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace Nim { + +class NimbleRunConfiguration : public ProjectExplorer::RunConfiguration +{ + Q_OBJECT + +public: + NimbleRunConfiguration(ProjectExplorer::Target *target, Core::Id id); + + ~NimbleRunConfiguration(); + + QString disabledReason() const override; + +protected: + void updateEnabledState() override; + +private: + void updateTargetInformation(); + + bool isBuildTargetValid() const; +}; + +class NimbleRunConfigurationFactory : public ProjectExplorer::RunConfigurationFactory +{ +public: + NimbleRunConfigurationFactory(); + +protected: + QList availableCreators(ProjectExplorer::Target *parent) const override; +}; + +} diff --git a/src/plugins/nim/project/nimbletaskstep.cpp b/src/plugins/nim/project/nimbletaskstep.cpp new file mode 100644 index 0000000000..8a6ce49de9 --- /dev/null +++ b/src/plugins/nim/project/nimbletaskstep.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "nimbletaskstep.h" +#include "nimbletaskstepwidget.h" +#include "nimconstants.h" +#include "nimbleproject.h" + +#include +#include +#include +#include + +#include + +using namespace Nim; +using namespace ProjectExplorer; + +NimbleTaskStep::NimbleTaskStep(BuildStepList *parentList) + : AbstractProcessStep(parentList, Constants::C_NIMBLETASKSTEP_ID) +{ + setDefaultDisplayName(tr(Constants::C_NIMBLETASKSTEP_DISPLAY)); + setDisplayName(tr(Constants::C_NIMBLETASKSTEP_DISPLAY)); +} + +bool NimbleTaskStep::init() +{ + processParameters()->setEnvironment(buildConfiguration()->environment()); + processParameters()->setWorkingDirectory(project()->projectDirectory()); + return validate() && AbstractProcessStep::init(); +} + +BuildStepConfigWidget *NimbleTaskStep::createConfigWidget() +{ + return new NimbleTaskStepWidget(this); +} + +bool NimbleTaskStep::fromMap(const QVariantMap &map) +{ + setTaskName(map.value(Constants::C_NIMBLETASKSTEP_TASKNAME, QString()).toString()); + setTaskArgs(map.value(Constants::C_NIMBLETASKSTEP_TASKARGS, QString()).toString()); + return validate() ? AbstractProcessStep::fromMap(map) : false; +} + +QVariantMap NimbleTaskStep::toMap() const +{ + QVariantMap result = AbstractProcessStep::toMap(); + result[Constants::C_NIMBLETASKSTEP_TASKNAME] = taskName(); + result[Constants::C_NIMBLETASKSTEP_TASKARGS] = taskArgs(); + return result; +} + +void NimbleTaskStep::setTaskName(const QString &name) +{ + if (m_taskName == name) + return; + m_taskName = name; + emit taskNameChanged(name); + updateCommandLine(); +} + +void NimbleTaskStep::setTaskArgs(const QString &args) +{ + if (m_taskArgs == args) + return; + m_taskArgs = args; + emit taskArgsChanged(args); + updateCommandLine(); +} + +void NimbleTaskStep::updateCommandLine() +{ + QString args = m_taskName + " " + m_taskArgs; + Utils::CommandLine commandLine(Utils::FilePath::fromString(QStandardPaths::findExecutable("nimble")), + args, Utils::CommandLine::Raw); + + processParameters()->setCommandLine(commandLine); +} + +bool NimbleTaskStep::validate() +{ + if (m_taskName.isEmpty()) + return true; + + auto nimbleProject = dynamic_cast(project()); + QTC_ASSERT(nimbleProject, return false); + + if (!Utils::contains(nimbleProject->tasks(), [this](const NimbleTask &task){ return task.name == m_taskName; })) { + emit addTask(Task(Task::Error, + tr("Nimble task %1 not found").arg(m_taskName), + Utils::FilePath(), -1, + ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); + + emitFaultyConfigurationMessage(); + return false; + } + + return true; +} + +NimbleTaskStepFactory::NimbleTaskStepFactory() +{ + registerStep(Constants::C_NIMBLETASKSTEP_ID); + setDisplayName(NimbleTaskStep::tr("Nimble Task")); + setSupportedStepLists({ProjectExplorer::Constants::BUILDSTEPS_BUILD, + ProjectExplorer::Constants::BUILDSTEPS_CLEAN, + ProjectExplorer::Constants::BUILDSTEPS_DEPLOY}); + setSupportedConfiguration(Constants::C_NIMBLEBUILDCONFIGURATION_ID); + setRepeatable(true); +} diff --git a/src/plugins/nim/project/nimbletaskstep.h b/src/plugins/nim/project/nimbletaskstep.h new file mode 100644 index 0000000000..47cf507a8d --- /dev/null +++ b/src/plugins/nim/project/nimbletaskstep.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace Nim { + +class NimbleTaskStep : public ProjectExplorer::AbstractProcessStep +{ + Q_OBJECT + +public: + NimbleTaskStep(ProjectExplorer::BuildStepList *parentList); + + bool init() override; + + ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override; + + bool fromMap(const QVariantMap &map) override; + + QVariantMap toMap() const override; + + QString taskName() const { return m_taskName; } + + void setTaskName(const QString &name); + + QString taskArgs() const { return m_taskArgs; } + + void setTaskArgs(const QString &args); + +signals: + void taskNameChanged(const QString &name); + + void taskArgsChanged(const QString &args); + +private: + void updateCommandLine(); + + bool validate(); + + QString m_taskName; + QString m_taskArgs; +}; + +class NimbleTaskStepFactory : public ProjectExplorer::BuildStepFactory +{ +public: + NimbleTaskStepFactory(); +}; + +} diff --git a/src/plugins/nim/project/nimbletaskstepwidget.cpp b/src/plugins/nim/project/nimbletaskstepwidget.cpp new file mode 100644 index 0000000000..6d33fdcbe6 --- /dev/null +++ b/src/plugins/nim/project/nimbletaskstepwidget.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "nimbletaskstepwidget.h" +#include "ui_nimbletaskstepwidget.h" + +#include "nimbleproject.h" +#include "nimbletaskstep.h" + +#include + +using namespace Nim; +using namespace ProjectExplorer; + +NimbleTaskStepWidget::NimbleTaskStepWidget(NimbleTaskStep *bs) + : BuildStepConfigWidget(bs) + , ui(new Ui::NimbleTaskStepWidget) +{ + ui->setupUi(this); + + auto project = dynamic_cast(bs->project()); + QTC_ASSERT(project, return); + + ui->taskList->setModel(&m_tasks); + QObject::connect(&m_tasks, &QAbstractItemModel::dataChanged, this, &NimbleTaskStepWidget::onDataChanged); + + updateTaskList(project->tasks()); + QObject::connect(project, &NimbleProject::tasksChanged, this, &NimbleTaskStepWidget::updateTaskList); + + selectTask(bs->taskName()); + QObject::connect(bs, &NimbleTaskStep::taskNameChanged, this, &NimbleTaskStepWidget::selectTask); + QObject::connect(bs, &NimbleTaskStep::taskNameChanged, this, &NimbleTaskStepWidget::recreateSummary); + QObject::connect(this, &NimbleTaskStepWidget::selectedTaskChanged, bs, &NimbleTaskStep::setTaskName); + + ui->taskArgumentsLineEdit->setText(bs->taskArgs()); + QObject::connect(bs, &NimbleTaskStep::taskArgsChanged, ui->taskArgumentsLineEdit, &QLineEdit::setText); + QObject::connect(bs, &NimbleTaskStep::taskArgsChanged, this, &NimbleTaskStepWidget::recreateSummary); + QObject::connect(ui->taskArgumentsLineEdit, &QLineEdit::textChanged, bs ,&NimbleTaskStep::setTaskArgs); + + + setSummaryUpdater([this, bs] { + return QString("%1: nimble %2 %3") + .arg(displayName()) + .arg(bs->taskName()) + .arg(bs->taskArgs()); + }); +} + +NimbleTaskStepWidget::~NimbleTaskStepWidget() +{ + delete ui; +} + +void NimbleTaskStepWidget::updateTaskList(const std::vector &tasks) +{ + QSet newTasks; + for (const NimbleTask &t : tasks) + newTasks.insert(t.name); + + QSet currentTasks; + for (int i = 0; i < m_tasks.rowCount(); ++i) + currentTasks.insert(m_tasks.item(i)->text()); + + const QSet added = newTasks - currentTasks; + const QSet removed = currentTasks - newTasks; + + for (const QString &name : added) { + auto item = new QStandardItem(); + item->setText(name); + item->setCheckable(true); + item->setCheckState(Qt::Unchecked); + item->setEditable(false); + item->setSelectable(false); + m_tasks.appendRow(item); + } + + for (int i = m_tasks.rowCount() - 1; i >= 0; i--) + if (removed.contains(m_tasks.item(i)->text())) + m_tasks.removeRow(i); + + m_tasks.sort(0); +} + +void NimbleTaskStepWidget::selectTask(const QString &name) +{ + if (m_selecting) + return; + m_selecting = true; + + QList items = m_tasks.findItems(name); + QStandardItem* item = items.empty() ? nullptr : items.front(); + uncheckedAllDifferentFrom(item); + if (item) + item->setCheckState(Qt::Checked); + + emit selectedTaskChanged(name); + + m_selecting = false; +} + +void NimbleTaskStepWidget::onDataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight, + const QVector &roles) +{ + QTC_ASSERT(topLeft == bottomRight, return ); + if (!roles.contains(Qt::CheckStateRole)) + return; + + auto item = m_tasks.itemFromIndex(topLeft); + if (!item) + return; + + if (m_selecting) + return; + m_selecting = true; + + if (item->checkState() == Qt::Checked) { + uncheckedAllDifferentFrom(item); + emit selectedTaskChanged(item->text()); + } else if (item->checkState() == Qt::Unchecked) { + emit selectedTaskChanged(QString()); + } + + m_selecting = false; +} + +void NimbleTaskStepWidget::uncheckedAllDifferentFrom(QStandardItem *toSkip) +{ + for (int i = 0; i < m_tasks.rowCount(); ++i) { + auto item = m_tasks.item(i); + if (!item || item == toSkip) + continue; + item->setCheckState(Qt::Unchecked); + } +} diff --git a/src/plugins/nim/project/nimbletaskstepwidget.h b/src/plugins/nim/project/nimbletaskstepwidget.h new file mode 100644 index 0000000000..73e15dcd05 --- /dev/null +++ b/src/plugins/nim/project/nimbletaskstepwidget.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include + +#include + +namespace Nim { + +class NimbleTaskStep; + +namespace Ui { class NimbleTaskStepWidget; } + +class NimbleTaskStepWidget : public ProjectExplorer::BuildStepConfigWidget +{ + Q_OBJECT + +public: + explicit NimbleTaskStepWidget(NimbleTaskStep *buildStep); + + ~NimbleTaskStepWidget(); + +signals: + void selectedTaskChanged(const QString &name); + +private: + void updateTaskList(const std::vector &tasks); + + void selectTask(const QString &name); + + void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles); + + void uncheckedAllDifferentFrom(QStandardItem *item); + + Ui::NimbleTaskStepWidget *ui; + QStandardItemModel m_tasks; + bool m_selecting = false; +}; + +} diff --git a/src/plugins/nim/project/nimbletaskstepwidget.ui b/src/plugins/nim/project/nimbletaskstepwidget.ui new file mode 100644 index 0000000000..223c2ed404 --- /dev/null +++ b/src/plugins/nim/project/nimbletaskstepwidget.ui @@ -0,0 +1,82 @@ + + + Nim::NimbleTaskStepWidget + + + + 0 + 0 + 399 + 252 + + + + Form + + + + + + QLayout::SetDefaultConstraint + + + QFormLayout::ExpandingFieldsGrow + + + + + Task arguments: + + + + + + + + + + Tasks: + + + + + + + QFrame::StyledPanel + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QAbstractItemView::NoSelection + + + QAbstractItemView::SelectRows + + + + + + + + + + + + + diff --git a/src/plugins/nim/project/nimbuildsystem.cpp b/src/plugins/nim/project/nimbuildsystem.cpp index 21b87702ea..740f42dec8 100644 --- a/src/plugins/nim/project/nimbuildsystem.cpp +++ b/src/plugins/nim/project/nimbuildsystem.cpp @@ -25,7 +25,7 @@ #include "nimbuildsystem.h" -#include "nimproject.h" +#include "nimbleproject.h" #include "nimprojectnode.h" #include @@ -51,12 +51,14 @@ NimBuildSystem::NimBuildSystem(Project *project) connect(&m_scanner, &TreeScanner::finished, this, &NimBuildSystem::updateProject); m_scanner.setFilter([this](const Utils::MimeType &, const Utils::FilePath &fp) { const QString path = fp.toString(); - return excludedFiles().contains(path) || path.endsWith(".nimproject") - || path.contains(".nimproject.user"); + return excludedFiles().contains(path) + || path.endsWith(".nimproject") + || path.contains(".nimproject.user"); }); - connect(&m_directoryWatcher, &FileSystemWatcher::directoryChanged, this, [this]() { - requestParse(); + connect(&m_directoryWatcher, &FileSystemWatcher::directoryChanged, this, [this] { + if (!isWaitingForParse()) + requestDelayedParse(); }); } @@ -100,14 +102,14 @@ void NimBuildSystem::parseProject(BuildSystem::ParsingContext &&ctx) QTC_ASSERT(!m_currentContext.project, return ); m_currentContext = std::move(ctx); QTC_CHECK(m_currentContext.project); - m_scanner.asyncScanForFiles(m_currentContext.project->projectDirectory()); } const FilePathList NimBuildSystem::nimFiles() const { - return project()->files( - [](const Node *n) { return Project::AllFiles(n) && n->path().endsWith(".nim"); }); + return project()->files([](const Node *n) { + return Project::AllFiles(n) && n->path().endsWith(".nim"); + }); } void NimBuildSystem::loadSettings() @@ -128,23 +130,33 @@ void NimBuildSystem::saveSettings() void NimBuildSystem::updateProject() { - auto newRoot = std::make_unique(project()->projectDirectory()); - - QSet directories; + // Collect scanned nodes + std::vector> nodes; for (FileNode *node : m_scanner.release()) { - if (!node->path().endsWith(".nim")) + if (!node->path().endsWith(".nim") && !node->path().endsWith(".nimble")) node->setEnabled(false); // Disable files that do not end in .nim - directories.insert(node->directory()); - newRoot->addNestedNode(std::unique_ptr(node)); + nodes.emplace_back(node); } - newRoot->setDisplayName(project()->displayName()); - project()->setRootProjectNode(std::move(newRoot)); - - m_directoryWatcher.addDirectories(Utils::toList(directories), FileSystemWatcher::WatchAllChanges); + // Sync watched dirs + const QSet fsDirs = Utils::transform(nodes, &FileNode::directory); + const QSet projectDirs = m_directoryWatcher.directories().toSet(); + m_directoryWatcher.addDirectories(Utils::toList(fsDirs - projectDirs), FileSystemWatcher::WatchAllChanges); + m_directoryWatcher.removeDirectories(Utils::toList(projectDirs - fsDirs)); + + // Sync project files + const QSet fsFiles = Utils::transform(nodes, &FileNode::filePath); + const QSet projectFiles = project()->files([](const Node *n) { return Project::AllFiles(n); }).toSet(); + + if (fsFiles != projectFiles) { + auto projectNode = std::make_unique(project()->projectDirectory()); + projectNode->setDisplayName(project()->displayName()); + projectNode->addNestedNodes(std::move(nodes)); + project()->setRootProjectNode(std::move(projectNode)); + } + // Complete scan m_currentContext.guard.markAsSuccess(); - m_currentContext = {}; } diff --git a/src/plugins/nim/project/nimbuildsystem.h b/src/plugins/nim/project/nimbuildsystem.h index b725cf4d9d..686bab3aca 100644 --- a/src/plugins/nim/project/nimbuildsystem.h +++ b/src/plugins/nim/project/nimbuildsystem.h @@ -58,11 +58,11 @@ public: void setExcludedFiles(const QStringList &list); // Keep for compatibility with Qt Creator 4.10 QStringList excludedFiles(); // Make private when no longer supporting Qt Creator 4.10 - void parseProject(ParsingContext &&ctx) final; + void parseProject(ParsingContext &&ctx) override; const Utils::FilePathList nimFiles() const; -private: +protected: void loadSettings(); void saveSettings(); -- cgit v1.2.1