Closed lgsobalvarro closed 1 year ago
Hi @lgsobalvarro,
Thanks for sending this in -- it's nice to see someone else other than myself has thought about this.
What you're suggesting makes a lot of sense to me. Putting aside any analogies to a CSS or SASS structure, the idea of having configuration blocks, as in:
Style {
...
}
Module {
...
}
Isn't anything new -- it's how twm
has structured its configuration file since
the beginning (and fvwm
being based on twm
would have inherited that
before moving away to the line-based syntax we have now).
I certainly don't disagree that moving to a block-based structure might be a good idea. However, I'm also thinking about a few things on top of that:
In terms of external scripting, what I'm thinking about here is bringing
consistency to the commands which fvwm
has -- similar to what tmux
does.
Indeed, I've referenced this here:
(https://github.com/fvwmorg/fvwm3/blob/master/dev-docs/NEW-COMMANDS.md) which
I recommend reading. The point is to:
Note that by duplication, I'm referring to styles (affecting windows), and commands which work on windows. There's a lot of overlap between the two which would help to reduce the confusion if there's a consistent means of referring to things like desktops, pages, windows, etc.
We also need to consider whether we need to write our own configuration
syntax, or if an existing library would be useful instead. libconfuse
seems
OK, but there's more power (and hence complexity) in writing our own config
syntax via flex/yacc.
I'm sure I'll have more thoughts in due course.
Thomas Adam notifications@github.com writes:
Hi @lgsobalvarro,
Thanks for sending this in -- it's nice to see someone else other than myself has thought about this.
What you're suggesting makes a lot of sense to me. Putting aside any analogies to a CSS or SASS structure, the idea of having configuration blocks, as in:
Style { ... }
Note that the current Fvwm accepts commands from multiple sources at the same time. Modules can send commands. They need to be atomic, not multi-line structures.
Back when I started using Fvwm, I came from an TWM variant that used structures. I was happy to get away from that.
-- Dan Espen
Hey @danespen,
Note that the current Fvwm accepts commands from multiple sources at the same time. Modules can send commands. They need to be atomic, not multi-line structures.
Indeed -- that's actually a really good point. It's worth remembering that configs aren't static (a point in time) but there are existing commands in fvwm
which can send input to other commands. The suggestion from @lgsobalvarro doesn't cover this -- and if fvwm3
ever learned of commands via argc/argb (akin to how cvs
works), this would need thinking about quite carefully in terms of how this would fit in with config file, vs sending commands to fvwm3
.
@danespen -- isn't what you're referring to the crux of how FvwmAnimate
works? I seem to recall that FvwmAnimate
can be sent commands to do things -- most notably from FvwmIconMan
but I suppose it's not limited to that.
Back when I started using Fvwm, I came from an TWM variant that used structures. I was happy to get away from that.
@danespen -- I have to ask (as I'm always curious!), aside from Fvwm
itself, I wasn't aware of a direct TWM
variant at the same time. Do you happen to recall what this was?
Thomas Adam notifications@github.com writes:
Back when I started using Fvwm, I came from an TWM variant that used structures. I was happy to get away from that.
@danespen -- I have to ask (as I'm always curious!), aside from Fvwm itself, I wasn't aware of a direct TWM variant at the same time. Do you happen to recall what this was?
There were a bunch. I was using cvtwm. I believe there was also a vtwm (without colored pixmap icons).
-- Dan Espen
Thomas Adam notifications@github.com writes:
Hey @danespen,
Note that the current Fvwm accepts commands from multiple sources at the same time. Modules can send commands. They need to be atomic, not multi-line structures.
Indeed -- that's actually a really good point. It's worth remembering that configs aren't static (a point in time) but there are existing commands in fvwm which can send input to other commands. The suggestion from @lgsobalvarro doesn't cover this -- and if fvwm3 ever learned of commands via argc/argb (akin to how cvs works), this would need thinking about quite carefully in terms of how this would fit in with config file, vs sending commands to fvwm3.
@danespen -- isn't what you're referring to the crux of how FvwmAnimate works? I seem to recall that FvwmAnimate can be sent commands to do things -- most notably from FvwmIconMan but I suppose it's not limited to that.
Yes I believe that was when the issue dawned on me during writing FvwmAnimate.
I forget if FvwmTalk or FvwmForm worried about the issue.
Fvwm has a couple of cases this matters:
When you use a backslash to continue a command, Fvwm could get confused if it got a backslashed command from another source. For that reason, if FvwmTalk wanted backslashes to work it would have to assemble the 2 lines before it sent them.
The other issue is the "+" command that continues functions, etc. I just avoid using the "+" command. Functions are normally defined in the base config file so it's not a serious problem.
It's best to remember, Fvwm takes commands, it doesn't read a configuration.
-- Dan Espen
Yes. I have thought of this you mention @danespen.
In fact I was asking myself: How could this I'm proposing work for... let's say... FvwmConsole? I think there could be a way to go about this (from a non-programmer perspective):
Of course this is not a perfect solution. For one it wouldn't be as cleaner as having a complete block syntax config. Still it would simplify styling and probably shorten config files.
Part of my intention with this proposal is to get the conversation going. As @ThomasAdam has point out, there are duplicates (and triplicates?) of commands. This could be a good excuse to start a little cleanup on that area and somehow streamline the config file/process. I myself, find it a bit annoying having to -for instance- define a style for each gnome application I use in order to force it to show proper window decorations, when this could be defined just once and simply list the applications you want to apply this style to.
lgsobalvarro notifications@github.com writes:
Yes. I have thought of this you mention @danespen.
In fact I was asking myself: How could this I'm proposing work for... let's say... FvwmConsole? I think there could be a way to go about this (from a non-programmer perspective):
1 Separate commands (quit, restart, read and so on...) from styling. I mean: keep most commands as they are. After all they are straight forward enough. 2 Being able to use an "atomic" structure, as @danespen suggests for styling in case a module needs to pass it for whatever reason. This atomic structure could be similar to the way inline css works.
I think you're arguing that styling doesn't have to be done as commands because styling is done once during startup?
If so, I don't think I agree. A styling app would restyle Fvwm interactively. I have one and there are a few others floating around.
Of course this is not a perfect solution. For one it wouldn't be as cleaner as having a complete block syntax config. Still it would simplify styling and probably shorten config files.
Using blocks would be shorter, but I'm not sure I agree about simpler.
What's simpler here:
AddToFunc Warp I Next [$0] Iconify -1
or
AddToFunc Warp I Next [$0] Iconify -1 AddToFunc Warp I Next [$0] WarpToWindow 24p 24p AddToFunc Warp I None [$0] Beep
I think the later is simpler because no new operator is introduced.
Part of my intention with this proposal is to get the conversation going. As @ThomasAdam has point out, there are duplicates (and triplicates?) of commands. This could be a good excuse to start a little cleanup on that area and somehow streamline the config file/process. I myself, find it a bit annoying having to -for instance- define a style for each gnome application I use in order to force it to show proper window decorations, when this could be defined just once and simply list the applications you want to apply this style to.
What you proposed looked pretty neat. When I saw it the second time I realized the problem it would create.
If I was trying to improve the command syntax of Fvwm I'd be looking at how Fvwm does parsing. I'd try to make the parsing as table driven as possible. Right now Fvwm uses a lot of functions that aid in parsing, for example, GetNextToken. But those functions are joined up with logic instead of a table.
An example of a table driven parser is the one used for TSO CLISTS. The table names all the keywords and names the variables where the parsed result is put. The table fvwm could use would contain things like this keyword must be followed by a geometry or a color name. It could do things like declare that a keyword must be followed by a number and define the range.
I haven't looked deeply but I suspect that trying to parse commands with tables might force some commands to change syntax.
I've done things like this more than once and it's not easy but it does reduce code size.
-- Dan Espen
You are right. It would most likely deeply affect how FvwmCristal, NoCDE and other similar styling utilities work. I just mention it as an example of how what I propose could be convenient to deal with that kind of situations where you'll pass the exact command 5, 10 times just to do something as simple as force gnome apps to honor window decors.
I'm well aware that changing syntax out of the loop and in a radical manner would be problematic, both for developers and users. But as I said, the idea with this post/feature request is to get the conversation going. Get some input of what a new syntax should and should not be/have from both users and developers. Either way the decition of changing the syntax is any way is not mine at all.
What you propose seems like a viable solution, however is out of my league. Could you give us an example of how could it work?
Cheers :)
lgsobalvarro notifications@github.com writes:
You are right. It would most likely deeply affect how FvwmCristal, NoCDE and other similar styling utilities work. I just mention it as an example of how what I propose could be convenient to deal with that kind of situations where you'll pass the exact command 5, 10 times just to do something as simple as force gnome apps to honor window decors.
I'm well aware that changing syntax out of the loop and in a radical manner would be problematic, both for developers and users. But as I said, the idea with this post/feature request is to get the conversation going. Get some input of what a new syntax should and should not be/have from both users and developers. Either way the decition of changing the syntax is any way is not mine at all.
What you propose seems like a viable solution, however is out of my league. Could you give us an example of how could it work?
I'll use the ClickTime command as an example:
The syntax for that command is
ClickTime Delay
If the Delay is missing it uses DEFAULT_CLICKTIME. Otherwise if the Delay is less than zero, zero is used otherwise the value is converted from a string to an int. The value is stored in Scr.ClickTIme as an int. Then if Fvwm is in startup, the value is changed to a negative value.
So the table entry for parsing that command might be:
int min_params 0 int max_params 1 (For each parameter in this case there is only 1) enum stored_as INT void * stored_where Scr.ClickTIme int int_default_missing DEFAULT_CLICKTIME int min_value 0 int max_value MAX_INT
There would be a pointer in the functable (check functable.h, functable.c) that would point to the above structure.
To support other commands, more things would need to be added. (A lot more things.)
The last part, using a negative value during startup, could be handled with a table entry that says change to negative during startup or by pointing to a unique function to be called after the command is parsed.
The actual function CMD_ClickTime wouldn't be needed. The only thing that might require logic is the special logic for startup. That particular command doesn't do any checking so:
ClickTime Hello
isn't diagnosed. Using a table, I'd expect that it would be since "Hello" is not an int. Probably MAX_INT isn't a good max either. Easier to implement a reasonable max with a table.
-- Dan Espen
Hey @danespen,
Yeah, that's certainly one approach. To my mind, an enumeration table makes sense. We could expand this idea more generally though to consider that there are:
Move
, Resize
, etc.We could generalise the idea that for settings, they operate globally, or per screen or per desktop, or per page, and hence allow for a hierarchical inheritance of this. So for example, take DesktopSize
, in FVWM3
this operates at a screen level (so you could say, has a screen
context) hence a hypothetical command might be:
set -g desktop-size 2 2
-- sets "desktop-size" to 2x2 for all monitors.set -t HDMI1 desktop-size 4 4
-- sets "desktop-size" to 4x4 for just HDMI1
, implication is the other attached monitors would therefore use 2 2
.Commands which operate on a window could work similarly:
Move -t :0:XTerm 0 0
Would move the XTerm on the current screen on desktop 0, to position 0 0
.
Move 0 0
Would work like Pick Move 0 0
does now, as no window was specified.
If each command was bounded by its understanding of how it is to operate, then we could easily insert defaults in to it upfront. So for example, with ClickTime
, we could have an options table which looked like this:
struct options_entry {
const char *name;
const char *default_str;
int default_num;
};
struct options_entry opt_table[] = {
{
.name = "ClickTime",
.default_num = 250;
}
};
Which means that if the user didn't specify a ClickTime, it defaults to 250
. In terms of options, we could just walk the table (as you've said, @danespen), and allow for each option to define its own scope.
I'll get to command/window scoping later on, similar to fvwm's exec_context
stuff later...
Leaving a few more thought here...
I was looking at decors earlier and realised that they're both very powerful and complex, yet utterly incomprehensible.
From the fvwm
manpage:
AddToDecor FlatDecor
+ ButtonStyle All Active (-- flat) Inactive (-- flat)
+ TitleStyle -- flat
+ BorderStyle -- HiddenHandles NoInset
If you can tell me at a glance what the end result of that is, you should get commit-bit rights to fvwm3's repository. ;)
I think there's merit to trying to group things together -- I am loathe to go down the Yacc/Bison/Flex route of writing a grammar parser to describe the syntax of a config file. Perhaps using libconfig is easier?
Thomas Adam notifications@github.com writes:
Leaving a few more thought here...
I was looking at decors earlier and realised that they're both very powerful and complex, yet utterly incomprehensible.
From the fvwm manpage:
AddToDecor FlatDecor + ButtonStyle All Active (-- flat) Inactive (-- flat)
I think active/inactive are for buttons in use or grayed out due to application hints. The all means to apply it to all buttons.
+ TitleStyle -- flat
Not sure what a flat titlestyle is maybe no shadows.
+ BorderStyle -- HiddenHandles NoInset
The handles separate the border from the corners of the border. THere's an inset for the separation?
If you can tell me at a glance what the end result of that is, you should get commit-bit rights to fvwm3's repository. ;)
Well, that's my glance.
I think there's merit to trying to group things together -- I am loathe to go down the Yacc/Bison/Flex route of writing a grammar parser to describe the syntax of a config file. Perhaps using libconfig is easier?
Not sure what you're getting at.
All that decoration stuff was done before I got involved so I don't know any history on it.
-- Dan Espen
Hi @danespen
Yeah -- the decor syntax is really confusing. I've only ever had to use it to change a few things, as I stick to the MWM-style of window decorations anyway.
My point about Yacc/Bison was to highlight that we have a choice of either defining our own syntax for the proposal that @lgsobalvarro has suggested, or we look at existing configuration libraries, such as libconfig
. Given the frustrations I've had with how fvwm
does its syntax parsing, I'm keen to avoid too much rework of writing our own config file format using yacc. But I need to give it some more thought.
Thomas Adam notifications@github.com writes:
Hi @danespen
Yeah -- the decor syntax is really confusing. I've only ever had to use it to change a few things, as I stick to the MWM-style of window decorations anyway.
My point about Yacc/Bison was to highlight that we have a choice of either defining our own syntax for the proposal that @lgsobalvarro has suggested, or we look at existing configuration libraries, such as libconfig. Given the frustrations I've had with how fvwm does its syntax parsing, I'm keen to avoid too much rework of writing our own config file format using yacc. But I need to give it some more thought.
Ah, I see.
I've always done hand crafted parsers. More fun.
So far I haven't seen any syntax changes that appealed to me, but then I don't really want to make changes to my config anyway.
-- Dan Espen
I joke about this on IRC yesterday night. Here is my "official" answer.
+ ButtonStyle All Active (-- flat) Inactive (-- flat)
Flattens button style when buttons are active and/or inactive.
+ TitleStyle -- flat
Flattens Titlebar. No idea what exactly "flats" here.
+ BorderStyle -- HiddenHandles NoInset
Hides Handles?
I don't know. I have always used the MWM decor. So I have not really played with window decors. And without trying this out, I can't really tell what it does exactly.
I think what I'd like to see is a preprocessor approach to a new syntax, similar (but not in implementation) to what FvwmPerl
does now.
For example, using lua, we could write a preprocessor for syntax which defined a config structure for:
style <...> {
...
}
function <...> {
I {
....
}
C {
....
}
}
etc...
... which then converts that to current fvwm syntax, sending it to fvwm dynamically (via FvwmMFL
).
This would allow us to work on this independently of any deeper changes to Fvwm until we're happy with it.
I don’t love lua (no strong opinion here yet), but I do like the approach you outlined @ThomasAdam.
It will be transparent to the user. It's not about forcing lua on people, this is the language choice for writing the preprocessor in for whatever DSL sort of thing we create. This has always been FVWM's approach; it's always had a DSL of sorts. Lua sounds reasonable as it has hooks in C, but also we could expand this for hook-support in the future.
I think what I'd like to see is a preprocessor approach to a new syntax, similar (but not in implementation) to what
FvwmPerl
does now.For example, using lua, we could write a preprocessor for syntax which defined a config structure for:
style <...> { ... } function <...> { I { .... } C { .... } } etc...
... which then converts that to current fvwm syntax, sending it to fvwm dynamically (via
FvwmMFL
).This would allow us to work on this independently of any deeper changes to Fvwm until we're happy with it.
I think this is a really good idea. This approach would allow us to develop a new syntax in an "independent" way to any changes made to FVWM core, as you point out. Also it would allow to the new syntax evolve accordingly to feedback and user needs without the need of doing major changes to FVWM. Or so I gather from your comments.
lgsobalvarro notifications@github.com writes:
I think what I'd like to see is a preprocessor approach to a new syntax, similar (but not in implementation) to what FvwmPerl does now.
For example, using lua, we could write a preprocessor for syntax which defined a config structure for:
style <...> { ... }
function <...> { I { .... } C { .... } }
etc...
... which then converts that to current fvwm syntax, sending it to fvwm dynamically (via FvwmMFL).
This would allow us to work on this independently of any deeper changes to Fvwm until we're happy with it.
I think this is a really good idea. This approach would allow us to develop a new syntax in an "independent" way to any changes made to FVWM core, as you point out. Also it would allow to the new syntax evolve accordingly to feedback and user needs without the need of doing major changes to FVWM. Or so I gather from your comments.
I'm missing the value of it. How does it help users to give them 2 different syntaxes to deal with?
Is the new syntax easier to learn or understand, does it help to write configuration GUIs?
-- Dan Espen
I'm missing the value of it. How does it help users to give them 2 different syntaxes to deal with? Is the new syntax easier to learn or understand, does it help to write configuration GUIs?
For what I gather, and @ThomasAdam can correct me if I'm wrong, it would be just one syntax the user would use. The other one (the current one) would be for FVWM "internal use".
I think what I proposed initially would be easier to learn and understand, if as a user you are at least a bit familiar with css or any similar markup that relays on blocks/brackets.
For what I gather, and @ThomasAdam can correct me if I'm wrong, it would be just one syntax the user would use. The other one (the current one) would be for FVWM "internal use".
This reminds me an awful lot of LISP S-Expressions and M-Expressions. That's not a terrible thing, but I just never see any dialects of LISP that really use M-Expressions these days (everyone basically settled on S-Expressions).
I think what I proposed initially would be easier to learn and understand, if as a user you are at least a bit familiar with css or any similar markup that relays on blocks/brackets.
My thoughts after reading through these comments:
I'd like to see it done as a translation into the internal syntax, if possible. For instance, if functions are declared like this
# function definition
do_a_thing() {
command
}
…That can be converted to the DestroyFunc do_a_thing/AddToFunc do_a_thing/+
syntax relatively easily by just listening for a closing curly brace with a stack. It also is reminiscent of shell scripts, which is an upshot in my opinion due to the high amount of use bourne shell scripts get in Unix environments. The ()
acts as a keyword to let the parser know that what follows will be a function definition.
If we want other kinds of "structured" data, either another kind of token could be used ([]
for instance), or perhaps instead of using such tokens we could simply do something like what bash can optionally use for declaring functions:
function name [()] compound-command
…With function
being the keyword for adding a function, and style
being the keyword for adding styling information, for instance. A style
keyword would then be parsed into a bunch of Style
commands (or comma-separated values and a single Style command) until the closing }
was reached.
This has the upshot of being more legible/less cryptic at a glance than, say, square brackets, at least to an average user of C-inspired languages or bash scripts (note that traditional bourne shell has no function
builtin; this is a bash-ism. Bourne shell only specifies the func_name() {command}
syntax).
For styles, therefore:
style xclock {
Sticky
!Title
!Borders
StaysOnTop
}
style * {
Font "StringEncoding=UTF-8:xft:MS UI Gothic:size=9:bold:antialias=false,xft:Tahoma:size=8:bold:antialias=false"
}
…Would be equivalent to (and be decoded to) the traditional notation as either:
Style "xclock" Sticky
Style "xclock" !Title
Style "xclock" !Borders
Style "xclock" StaysOnTop
Style * Font "StringEncoding=UTF-8:xft:MS UI Gothic:size=9:bold:antialias=false,xft:Tahoma:size=8:bold:antialias=false"
Or, even better, simplified with commas to:
Style "xclock" Sticky, !Title, !Borders, StaysOnTop
Style * Font "StringEncoding=UTF-8:xft:MS UI Gothic:size=9:bold:antialias=false,xft:Tahoma:size=8:bold:antialias=false"
With the comma separation, we'd likely want to limit the length of individual lines to aid in debugging; for debugging purposes, the former translation might be better (and would certainly be easier to write). And with this notation, we could write functions as:
function FunctionName {
+I Action
}
Translating to:
DestroyFunc FunctionName
AddToFunc FunctionName
+ I Action
…Perhaps this could be loaded from a separate "resource" file from the main FVWM config file by use of a new command (maybe called Parse
, LoadResource
, or ImportStructured
? Just ideas; there's probably a better name out there, but this is a stream of consciousness post so I hope it makes sense/is coherent). The main upshot of the new format would be legibility at the cost of lower flexibility, which should rightly be a choice for the user to make. If desired, the user could simply have a one-line .fvwmrc
/~/.fvwm/config
file containing LoadResource $[FVWM_USERDIR]/structured-config
.
Of course, this way, using the traditional syntax it would still be possible to do additional AddToFunc
's and similar as needed (or AddToFunc
could be called from within the new format since it's translated when it's parsed). Alternatively a secondary keyword called append
could be used which causes the parser to not generate the DestroyFunc
line when followed with the function
keyword.
I hope this was coherent and didn't ramble to much. I wrote it as I thought of things. Basically I think a shell-like syntax might be easier and also closer to the internal representation FVWM uses while retaining some benefits for end users in terms of the readability of things.
Wyatt Ward notifications@github.com writes:
For what I gather, and @ThomasAdam can correct me if I'm wrong, it would be just one syntax the user would use. The other one (the current one) would be for FVWM "internal use".
Yagg!
Think about it.
Are you going to duplicate all of Fvwm's internal error checking? If not, the user types one thing, Fvwm responds with an error message about some generated command nothing like what the user entered.
It's madness I tell you!
-- Dan Espen
Ah, that is fair. I didn't even think about how errors would be handled with this system. I'd probably have to have it be reversible, in that case… or have some automatically generated comments on the ends of lines that correlate them to the structured format line numbers.
Edit: Actually, upon reflection, didn't I basically just describe the kind of thing a C preprocessor would do? Maybe i should see how C compiler errors sourced from header file includes get traced back.
I suppose one could also add a way to tell fvwm to parse the config and print the result, including all parsed/sourced definitions, although that would still be like debugging at a different level than the source code (in an intermediary language).
Thanks for the input; this was basically an RFC (in the literal "request for comments" sense; just to get feedback) from me, anyway.
Wyatt Ward notifications@github.com writes:
Ah, that is fair. I didn't even think about how errors would be handled with this system. I'd probably have to have it be reversible, in that case… or have some automatically generated comments on the ends of lines that correlate them to the structured format line numbers.
Well, took me a while to connect the dots.
First time I saw someone implement something like that was some time in the 70s. Never let the back end do edits.
cpp barely pulls it off. Many the time I had to examine the cpp output to understand where compiler errors were coming from.
I think Fvwm is stuck with processing commands (as it should be).
-- Dan Espen
I think Fvwm is stuck with processing commands (as it should be). I'd be happy with leaving it alone and unchanged as well; I mainly wrote that up as a thought exercise. I have no (large) issues with how FVWM configuration currently works, since I am happy with how my desktop currently behaves.
I suppose that such a program would be easily implementable by the user, anyway, and might just be extra bloat and maintenance burden to include in the core functionality of FVWM.
Many the time I had to examine the cpp output to understand where compiler errors were coming from.
I edited my message and alluded to that as well… since I believe you're using email notifications, I'll quote it.
Edit: Actually, upon reflection, didn't I basically just describe the kind of thing a C preprocessor would do? Maybe i should see how C compiler errors sourced from header file includes get traced back. I suppose one could also add a way to tell fvwm to parse the config and print the result, including all parsed/sourced definitions, although that would still be like debugging at a different level than the "source code" (in effectively an intermediate language).
I 100% understand where you're coming from; I'm not convinced it's a good idea either, just potentially less disruptive than some of the other syntaxes people have mentioned in this issue since the actual FVWM command syntax would not need to change.
On the danger of coming late to the party, and maybe missing something here:
I think there's merit to trying to group things together -- I am loathe to go down the Yacc/Bison/Flex route of writing a grammar parser to describe the syntax of a config file. Perhaps using libconfig is easier?
Maybe JSON would be an option? It is at least marginally human-readable, can hold nested data structures and can be used with or converted from a lot of formats and languages. (e.x. when I write python programs, I have all my settings in a dict, which I can simply push out into a JSON-file and be done with it, and read it in the same way, no grammar parsing required). Not knowing how FVWM handles it's config this might be an easy / accessible solution.
Maybe JSON would be an option?
No thanks. It's not very extensible, would become unweildy, and the JSON specification doesn't allow for comments.
Hm, sorry. I did not intend to write that much... But I'm really trying to get to a point in the end!
Aaaah, what syntax? A questinon that provides fertile grounds for disputes of religious dimensions. Good luck with that ;-)
No, honestly: I'm happy to see FVWM3 getting a DSL for configuration, and I sincerely believe this is a good idea. And a difficult task.
Let me elaborate:
All languages are crap, at some point at least. This can be easily verified by observing how many languages there are — if there was a really good one, then everybody would use it. But people are not happy with the languages they have, so they invent new ones. Even within a single use case (querying, programming), people cannot agree on a language.
And configuration? Well, none of the available languages seems to cut the mustard for FVWM3.
Having worked on XML professionally (implemented Schema validation, built an XQuery compiler), I've got a pretty stong opinion about XML: It is pure shite. Overengineered and overly complex. Just try to read the entire standards body.
But there's one thing about XML that I want to point out, which distinguishes it from languages like JSON: XML allows to introduce new, named constructors. I'll explain what I mean by that.
At an abstract level, most languages (and all I'd consider relevant here) represent something with the structure of a rooted tree, or a directed acyclic graph.
Primitives are the nodes that have no outgoing edges, they are not constructed from other things. In C, an integer literal would be such a thing
42
or a variable
x
Then, each language provides means to construct new things from these primitives. In C, you can build an assignment
x = 42;
JSON also provides primitives (numbers, strings, …) and means to construct new things, like an object
{ "x": 42 }
But the things you can build in JSON are limited, it's lists and objects. Nothing more. Whether two objects are the same depends only on the members of the object. Contrast this with XML, where tags act as constructors:
<meter>42</meter>
<foot>42</foot>
This could represent two different objects, each constructed from (its own instance of) the same primitive 42, by using different constructors, meter
and foot
. And you can have any number of these constructors.
In JSON? No can do. One might try
{ "unit": "meter", "value": 42 }
which is something different: It's just an object with two members. To be recognised as a length, a convention is required, like to look for a unit
and a value
member. When validated by a consumer, and transformed into something representing “42 meters”, then a reconstruction of a different datastructure has taken place. (And yes, not having comments in JSON is a major pain in the back.)
Being able to define and name constructors does not only allow to distinguish things which are identical on the inside. It also allows to create identical things in different ways, just think of Java classes having different constructors, like
Date(int year, int month, int date)
Date(long millisecondsSinceEpoch)
Date(String s)
which, as a side note, do have different names, because the signature is kinda part of the naming. Unfortunately.
I'd really hope that FVWM3's configuration would provide named constructors. I'll come back to that...
With the following list, one may wonder whether I'm not striving for a fully fledged programming language. And rightly so. It boils down to the question what we consider configuration. This is another issue of much debate.
Primitives: Numbers, booleans and strings.
Constructors to build simple generic data structures, like heterogeneous lists. This could be a syntax using brackets, like [1, 2, 3]
.
Constructors to build objects special to the domain, for a window manager these might be menus and their items, colors, fonts, keypress identifiers, and what not.
A strict, static type system that is strong enough to reject an invalid configuration instead of yielding a runtime error.
Variables, so that I can define a color once and use it many times.
Abstraction, so that I can construct similar things easily.
Evaluation of expressions, so that I can concatenate path names, or calculate some arithmetic expression.
A very simple, compact and elegant syntax. Really have a look at Haskell for that.
Having an “imtermediate” or “core” config language, as has been suggested, is certainly politically smart, because it does not slam the door in the face of anyone who does not like it (but in the end, most people will not like the config language anyways, see above).
It may not even be as insane as it looks at first: Many compilers use an intermediate representation to compile the input language to.
Of course, each compiler frontend does all the checking it can do, trying hard not to produce a flawed intermediate representation (which produces awkward error messages when it happens). But this is likely the only way to do it, some errors may not even be practial to find in some representations.
But the reason to use intermediate representations is rather technical, than political: When different language features may be expressed by the same means of a core language, then “desugaring” makes writing a compiler easier. E.g., in C we can replace
a[i] ↦ *(a + i)
or in Haskell, where the entire construct of list comprehension can be removed from the syntax
[ x + 1 | x <- [1..100], even x ]
↦
concatMap (\x -> if (even x) then [x + 1] else []) [1..100]
Also, intermediate languages should be crafted in a way to make desirable operations easier, or to expose properties not easily accessible in the surface language.
What does this mean here?
An intermediate configuration language should not be crafted to be very easy to read, but rather to be minimal in the number of means it provides, and close to the structures iniside FVWM3 that need to be controlled. This could be extremely simple plain text reverse polish notation (RPN) which lends itself nicely to build trees and DAGs. Or less simple RPN, as in PostScript. But it could also be something more standardised, like ASN.1 or Protocol Buffers (both of which I've never used).
But in any case, this intermediate language should be really well designed, i.e., it must be able to express all configuration needs that FVWM3 has, be it commands, or description of styles or menus, and what not.
Which brings me to the final point:
I think it would be helpful to have a very clear picture of what the config language should be able to express. Formal, detailed and precise. So much so, that it is basically an API.
This API must be the only interface to configure FVWM3.
Thus, FVWM3 being written in C, C would also be FVWM3's first prototypical configuration language.
The functions, values and types provided by this API represent the constructors and primitives mentioned above. C adds its means of abstration and combination, and a simple type system.
If time proves the API stable, and simple, and elegant enough, it would become clear what features a config language should provide.
If the API is clean and complete, in the sense that everything that FVWM3 must be able to digest can be fed in through that API conveniently, then designing a suitable surface language should follow naturally, I hope.
Any disputes about syntax should be postponed until then.
The plan would be to consider the API the intermediate language, but instead of compiling a configuration DSL into C code, the DSL would be interpreted into API calls.
I cannot tell what the result will be. Maybe it turns out to be Lua (God help us), or a Python library that feeds ASN.1 into FVWM3 via a socket, or a nice DSL like the one for FVWM2, which has proven very usable for me.
Seems to me you're basically suggesting that we do FVWM configuration in Haskell or C++, since you mention constructors and abstraction (i.e., implied concept of objects).
If we really do want to make things annoying and obtuse for early adopters that don't know a ton about programming already, and also wish to totally break compatibility with configurations that we already have, then I have my own suggestions.
I know people who use and know Haskell certainly exist, but if we're talking about these sorts of languages, and since you mentioned favoring the removal of "List comprehension" as a concept, I'd suggest the opposite. Make everything a list. I think you'll find there are far more people who have had at least a basic exposure to Lisp (mainly due to the influence of emacs), so I think some variant thereof might be preferable.
The basic concept of configuring a complex and flexible program via Lisp S-expressions has already been shown (again, emacs).
Lisp in particular strikes me as a decent choice because it is capable of being prototypical, declarative, imperative, and anything else anyone wants, while also being highly simple in its basic premise.
Also, assuming there's a 1:1 mapping between the existing commands and Lisp symbol names, this would make translating existing configurations relatively easy while also allowing for far greater flexibility without necessarily depending on calling external scripts. And if the Lisp side of things was given the ability to interface directly with X (via Xlib or XCB, or via something like clx
for Common Lisp), then that's a foothold to allow adding new features/functionality via the Lisp side of things.
Of course, to accomplish this, a truly massive amount of work would have to be done to either bind the C code to Lisp or to rewrite most of the program in a Lisp dialect. It also requires either implementing or integrating an existing Lisp. So this is all at least as unlikely in my mind as the suggestion above.
again, I honestly don't think this will or even necessarily should happen, and the status quo still seems at the very least acceptable to me.
The idea of translating to an intermediary language seems a little scary to me, and this is as someone who has and loves HP RPL calculators. They're great for what they can do, but I would never want to debug something as massive as my FVWM configuration in something like RPL or Forth, which would make debugging a nightmare.
Ok, I think we are going a bit off track here. So lets go back a bit and remember what the goals are taking into account some really important comments that have been made here.
Style Foo !Title
, Style Bar !Title
), and more importantly make it more friendly for newcomers. Also try to avoid situations like this example @ThomasAdam give us (I'm sure we all have a good idea what that does, but not exactly what, just by looking at it.)Hi everyone,
Thanks for the comments thus far. I don't want to see a DSL implemented. The barrier to entry for users is already far too high, and enforcing what amounts to a programming language would push too many people away -- so we will try and minimise that as much as possible.
I'm interested in only the following:
I see that more around command-line style syntax, as in:
move -s :2 -w res:/XTerm/ -t MONITOR2:4
Whereby "-s" is a source desktop (2
in this case, on the current monitor), moving all windows which have a resource of XTerm somewhere in the string, to desktop 4 on MONITOR2
.
Once you've worked out how the source/target parameters can be consistently applied, then you have the automatic notion of context -- for things like windows, desktops, mouse, etc.
Functions remain definable in their own right -- perhaps the syntax changes to a block-scope style, I don't know.
But none of this is fundamentally moving the user toward a DSL. It's enforcing consistency with functionality.
No, I'm not suggesting to “do FVWM configuration in Haskell or C++”, to the contrary, I'm advising against it. My entire point is, that the first goal should be to build an API in C that allows convenient configuration in the sense that it is a simple API with only a few, simple concepts that combine nicely. Not to make the user write C for configuration, but to guide the implementation of the configuration system.
FVWM's config is already a DSL, it's just not turing complete. And I would be wary to suggest a turing complete language. If you'd want to go there, build an interface to Python or Lua. This should even be possible against said API…
Hi @s5k6
I do understand your PoV, I just don't want to turn FVWM into a DSL. I know you can argue that any application has elements of DSL about them, and FVWM certainly does. But I am more interested right now in making the command subset FVWM has to be more akin to something like tmux.
After the fact, if language bindings become popular, that's a separate issue.
At this point, I think we've all chatted enough about this. Is there anyone who's going to help me code this, or is it all rhetoric? That'll be where the real value comes from -- the actions to go with the words mentioned here. :) If there's any takers, do please let me know!
Sorry, another week has passed, and I did not find enough time.
I was looking into the code (briefly!), but I have no clear idea of the concepts that are implemented. What I'm getting (maybe incorrectly) is, that reading a file and executing the commands therein happens around the function run_command_stream
in read.c
, right?
I got a bit lost in __execute_function
in functions.c
, which seems to be still occupied with some kind of parsing, using functions named PeekToken
. What is the idea behind this?
Hi @s5k6
Sure -- I know most of us are busy! Have a look here for some notes Dominik and I put together a while ago: https://github.com/fvwmorg/fvwm3/blob/master/dev-docs/PARSING.md
With the aim of streamlining/modernizing FVWM3 syntax and trying to make it a bit more friendly for new users. I put forward the following ideas of how it could work.
This proposal is inspired by CSS/SASS.
Module invocation
Functions
Styles
Module Instances