dykstrom / basic-mode

Emacs major mode for editing BASIC code
GNU General Public License v3.0
7 stars 10 forks source link

Investigate ways to indicate source file specific dialect #10

Closed ghost closed 1 year ago

ghost commented 6 years ago

As basic-mode continues to expand to support more dialects of basic, I believe it will be helpful if the user can specify within the source file which dialect the file is targeting.

This may need a combination of approaches involving

  1. File variables Specifying-File-Variables
  2. Interactive functions (i.e. M-x basic-set-dialect)
  3. Customizable arguments (basic-mode-default-dialect)

Also for consideration

  1. projectile-esque .basic-mode file in a "project folder" that specifies the dialect and other customizable settings for source files in the current directory and below
  2. history cache in ~/.emacs/basic-mode-source-history that remembers which dialect was specified for which source files have been opened by the user

The output of this issue will be a recommended solution for consideration by the maintainer and other basic-mode contributors.

dykstrom commented 6 years ago

This seems like an ambitious change. Can we do this in a branch so the changes will not be automatically deployed to MELPA each time I merge something? I'm not sure how github works. If I have a branch and you have a branch, can you make pull requests to my branch instead of master?

ghost commented 6 years ago

Yes! I think so. I'm still researching this. There won't be code to commit at this point as the output from this issue will only be some researched suggestions for your consideration.

Based on what I've read so far I think the best way to move forward with this will be to simplify basic-mode as much as possible, then specialize it with define-derived-mode for each dialect for which support exists. There would be a generic basic-mode, and then N derived modes, 1 for each dialect. (i.e. basic-qb45-mode, basic-basica-mode, basic-gw-mode, basic-qb71-mode, basic-pet-mode). Doing it this way makes it easy to split the dialect specific stuff off into separate source files and it also keeps the complexity out basic-mode since the behavior will be overridden in each dialect derived mode instead of configured with customizations in basic. It'll ensure that you never need to:

;; yuck! Let's avoid this.
(cond ((string= major-mode "basic-45-mode") x)
          ((string= major-mode "basic-mode") y))
...

For instance, there may be a basic-qb45-mode that is derived from basic-mode and extends the syntax table, adds additional indentation, etc...

As for telling emacs which mode to use automatically, I've settled on the below strategy.

1) If a user frequently works with multiple dialects, the user will set the mode using the file variable. The benefit of this is that is already implemented by Emacs. No additional work is required to support it.

REM -*- mode: basic-MYDIALECT-mode -*-

2) If the user works primarily with a specific dialect, then the user can use the standard auto-mode-alist configuration.

;; I mostly work with QB45 so that is the default mode I use
(add-to-list 'auto-mode-alist '("\\.bas\\'" . basic-qb45-mode))

3) Finally, the default setting is to just use the more general basic-mode if nothing else is specified.

Please let me know what you think, and thank you for your consideration!

dykstrom commented 6 years ago

Hi, sorry for taking so long to respond! To be honest, I am not sure I am qualified to decide what is the best way to go forward. I do not consider myself an Emacs Lisp expert, even though I happen to have written a major mode. However, since I am now the maintainer of this mode, I will have to decide on something.

I would like basic-mode to work in such a way that an occasional user, that just wants to try it out, edit some BASIC code, and feel nostalgic, should be able to do this very easily. Ideally, he should not have to customize anything, but get reasonable functionality out of the box. At the same time, regular users should be able to customize, or otherwise make their Emacs adapt to the BASIC dialect of their choice.

I think your suggested solution at least satisfies the second requirement. As for the first requirement, I think it depends on how much we put into the general basic-mode, and which defaults we use.

Some questions:

  1. With this solution, will there be several files, for example basic-mode.el, basic-qb45-mode.el, etc?
  2. The default autoload provided by the package system would be for the general basic-mode I guess. So if the user wants a specific dialect, he would have to add another autoload for his preferred dialect in his .emacs file?
  3. Have you thought about what to do with functionality that is common to several dialects, but not relevant for other? As an example we can take line numbers. There is a lot of code to handle line numbers. This code would be used by the BASICA dialect, the Sinclair dialect, and also the QB45 dialect. But it would be irrelevant to the VB dialect. Would we then put line number code in the general basic-mode so that it is inherited by all dialects, and somehow ignored by basic-vb-mode, or would it be defined in several dialects, or maybe included from a separate file?
ghost commented 6 years ago

With this solution, will there be several files, for example basic-mode.el, basic-qb45-mode.el, etc?

Yes. This is to help reduce the complexity of extending basic-mode for each dialect. It also provides a more direct approach for contributors to implement their personal favorite dialect of basic. Wikipedia shows that there are many dozens of dialects out there.

https://en.wikipedia.org/wiki/List_of_BASIC_dialects

The default autoload provided by the package system would be for the general basic-mode I guess. So if the user wants a specific dialect, he would have to add another autoload for his preferred dialect in his .emacs file?

Correct. The user has to override the autoload to use their preferred dialect. This is a one liner in their Emacs init script (init.el, .emacs, etc...).

Have you thought about what to do with functionality that is common to several dialects, but not relevant for other? As an example we can take line numbers. There is a lot of code to handle line numbers. This code would be used by the BASICA dialect, the Sinclair dialect, and also the QB45 dialect. But it would be irrelevant to the VB dialect. Would we then put line number code in the general basic-mode so that it is inherited by all dialects, and somehow ignored by basic-vb-mode, or would it be defined in several dialects, or maybe included from a separate file?

This is definitely an engineering problem. Tentatively, I would suggest a tree of derived modes. For example:

To be clear, the goal is not to immediately create all of these! But instead to provide a simple pattern that allows these modes to grow organically over time. I plan on contributing the qbasic mode set myself as I was already working on a similar effort.

Finally, this looks good on paper, but you won't know for sure how well this will work until it is attempted. If you'd like, I can attempt a refactoring to produce the set of modes basic-mode -> basic-qb-mode -> basic-qb11-mode in order to test the concept.

Thank you for taking the time to review my ideas. :)

dykstrom commented 6 years ago

OK, so this sounds like a solution that might work. I'm a little afraid that it will be complicated with the inheritance and all. After all, it is not Java or C++ we are talking about here, but Emacs Lisp. But maybe it will work out fine. Please go ahead and make a POC for the inheritance concept, so we can test and discuss an actual implementation. It will be interesting to see how it turns out.

hackerb9 commented 1 year ago

Please see #20 for a proof of concept. It is based on the TRS-80 Model III Basic Reference card.

@ghost: You seem to have a much better understanding of the different variations of BASIC than I do. Do you think you could create a listing of the functions, builtins, and keywords for each of the major dialects you listed? For the hierarchical ones you could just show the difference from the parent (e.g., +screen, -usr)

Also, it would be good to know if they have syntactical differences, such as apparently QuickBasic allowing . in an identifier, so it can't be treated as punctuation.