Create functions from c3c to manipulate the project.json
Yes, it's straightforward to edit the project.json, but the downside is that it's currently actually json5. Plus there is some need to consult the documentation just to do simple things, and there is no way for a beginner to really know what the parts do.
So a first feature could be something like: c3c project view, which looks at the project.json and prints something like:
Authors: John Doe <[email protected]>
Version: 0.1.0
Project language target: 1
Warnings used: no-unused
Search paths, .c3l files: lib
Dependencies, .c3l: *none*
Source folders: src/**
Source folders, c files: csource/**
Output location: build
Default optimization level: O0
Targets
Name: foo
Type: executable
And then you could do things like c3c project add-target <name> executable
c3c project update-target <name> set target windows-x64
Really trivial things to do, but this allows for a separate help on the project:
c3c project project help-target which might list:
project update-target <name> set target [target name]
project update-target <name> set type [executable | static-lib | dynamic-lib]
As a first step, just getting project view done is enough.
Alright, I'm thinking of taking a look at doing this, a question though, all the commands use the BuildOptions parser, but the way this is being described is almost as a separate set of commands of the form c3c project [subcommand], of which none of the other functions are prefixed like this, and the parser for build-options would also treat the add-target, executable, set, target, etc... part of the given commands as files instead. Therefore I'm thinking a specialized options struct and parser for this subset of commands might be a decent idea especially since none of the general options for building apply here, does this sound right to you, or would you like for this to still be fit into the BuildOptions struct?
I think it should be fairly straightforward to fit it in the build-options still. You just need to forward to a separate function that does the more complex parsing, e.g.
if (arg_match("project"))
{
options->command = COMMAND_PROJECT;
parse_project_options(options);
return;
}
Gotcha, then I'll go ahead and do it that way
How should project view handle JSON that doesn't conform to the schema, say someone has authors as a string rather than a list of strings for example?
Should it print something like Authors: <expected a string array> or should it just error out?
Error out, saying it is invalid and what key is invalid.
I've been thinking of having a key "vendor" which has a completely free schema. That way IDEs and stuff can put things in there and it's just ignored by the compiler, but they can use it.
I am looking for a good first issue and was playing with add-target locally. How should add-target and update-target be implemented?
I see 2 options:
- Use string template (as its done in
project_manipulation.c) and insert into theproject.jsoninto specific line/column - Read the whole
project.jsonto build JSONObject hierarchy. Insert/Update JSONObject of the target. Serialize root JSONObject into file.
For the second option, I couldn't find any ready to use functions to convert JSONObject to string (json.c seems to be focused on parsing only). Should I write something similar to what is in json_output.c?
For vendor should we just accept a string that may be a JSON object (not just string value)? Or we should implement some sort of pathing, for example project update-target target1 set vendor.visual_studio.version 2022 to update to
{ ... "targets": { "target1": { ... "vendor": { "visual_studio": "version": "2022" } ... } } ... }
I think it should be "read the file as json, modify, print the json". It's fine to discard the comments. When it comes to a target you want to give:
- name
- type (exe/static-lib/dynamic-lib)
- Optionally the target (e.g. windows-x64)
Other commands can be used to manipulate the target further.
For vendor, maybe it should be:
"vendor" : {
"com.foo.bar": ... arbitrary json ...
"com.baz.Foo": ... arbitrary json ...
}
So a unique key, preferably reverse path like above, then any data inside of that.
Could this be expanded upon to have more options?
I was thinking of a list-targets subcommand for project, that could take in an additional flag to print the shorthand version or the long version.
A mockup:
$ c3c project list-targets
Targets:
- hello
Name: hello
Type: executable
- world
Name: world
Type: executable
And
$ c3c project list-targets --short
hello
world
You'd have to decide whether '--short' prints the short version, or if the default one prints the short version and '--verbose' prints the full.
This subcommand could also be a subcommand or flag for project view, where the idea then is to show only a part of of what view shows.
The usecase for this would mostly be for other tooling (like completions) to query specific parts of the project-config. One example would be a completion script that after $ c3c run would look at c3c project list-targets --short to complete the command, enabling very smart completions without having to parse the whole output of c3c project view.
EDIT:
After talking on Discord about this, I will try to implement this as a c3c project --list-project-targets or c3c project list-project-targets, not sure yet.