Go to page:

Search:   Help

Developers' side bar

Selected categories

Edit

# Macros

Categories: Development, Macro, LyX_1_6
<< | Page list | >>

Ideas for a new implementation of math macros.

### Use Cases

green = works with current implementation
orange = does not work with current implementation, but could be added without major rewrite
red = hard to implement or only with major reorganisation

B = Status with my proposal from below: "move all the shifting/update logic to Buffer::buildMacros" with solution 3
D = Status with my proposal from below: "move all the shifting/update logic to Buffer::buildMacros" with solution 3, my working copy

1. BD Define a new macro with a known arity ("arity" = number of arguments). Use instances later on in the document.
2. BD Redefine a macro to use the same macro name with different definitions in different areas of the document.
3. BD Have \newcommand in the preamble (i.e. by importing tex code), and then define the command as a native lyx math macro. All the uses of the old command should then turn into instances of the lyx math macro.
4. BD Rename a macro and also adapt all the instance of the macro in the document
5. BD Change the arity of a macro (normaly probably increase it), maybe with a default value used in instances of the macro (possibly empty)
6. BD Removal of a macro.
7. BD Insertion of a macro. Still missing menu voice "Insert->MathMacro" (how would a user know about their existence, otherwise ?)
8. BD Moving of a macro.
9. Editing of a macro instance
1. BD as a list of #1: __, #2: __
2. BD inline, the macro definition will be read-only, only the arguments (as holes) are editable
10. BD Changing of the editing behaviour of 9 for certain macros, not only globally.
11. BD Defining dynamic macros inside of macros?! Andrew: can you comment on that? You mention it in your patch
12. BD Using macros with the same name, but different definitions in different open documents.
13. BD Using macros from the master document.
14. BD Using the same argument, e.g. #1, more than once in the definition, like \newcommand{\ntothen}[1]{#1^#1}
15. BD Patterns like \def\foo #1/#2{\frac{#1}{#2}}
16. BD Higher order substitution (or call-by-name text substition) like \def\foo #1{#1 12}, which is applicatable like \foo\frac to give 1/2
17. BD Optional parameters like \newcommand{\foo}[2][x]{#2_#1}

### Random ideas/Questions

• What about non-math macros? \newcommand{\mytitle}{The Title of my Thesis}. They would be really useful !!
• How are macros implemented in Scientific Workplace?
• It seems that they don't exist and instances one-time resolved during import Stefan?
• I am not yet sure how renaming/arity changes should look like for the user, i.e. the following two usecases:
• Rename a macro and also adapt all the instance of the macro in the document
• Change the arity of a macro (normaly probably increase it), maybe with a default value used in instances of the macro (possibly empty)
• One could follow the TeX+editor way, i.e. if you change a macro nothing else changes in the text. I.e. after renaming a macro all the instances will be rendered as unknown. Some people might like that because this way you could easily hold two version of a macro, and switch between them easily by renaming. Opinions?
• What about arity changes? Some kind of automatic might make sense, i.e. if there is a new argument it should be filled with some default value.
• See proposal D) below: non-greedy and greedy (TeX like) arity manipulations are possible.

### Current Problems (in trunk)

1. Macro definitions are shared among all open document, i.e. one big global macro table
2. Macro instantiations have a fixed arity which must be known on creation
3. Macros which are not defined yet, will be turned into InsetMathUnknown and will stay like that, even if the macro is defined later
4. A buffer local macro table is not possible because the macro instantiation needs the arity. But the current buffer is not accessible everywhere where macros are instantiated.

### Proposals

#### A) Andrew

• What are those macros in macros about? Is this a feature which only became possible by the way macros are expanded, or is there really a sensible use for it?
• Editing the arity in a normal MathArray cell is strange. You can type everything there, not only numbers. I think a inset dialog with the property would make more sense Stefan?

#### B) Stefan: update arguments to macros (shift in and out) inside the MathArray::metric

• Problem: if a macro is removed and added with a larger arity, the MathArray cells behind the macro instances are eaten up. Probably not what one expects.
• Main advantage/difference to Andrew's proposal: A file which has unknown insets/macros can be loaded and the macros can be defined then. All previously unknown insets/macros are automatically turned into proper macro instances. In other words: unknown tex commands \foo behave like \newcommand{\foo}{\foo} in the lyx buffer.

#### C) Stefan: move all the shifting/update logic to Buffer::buildMacros

The method Buffer::buildMacros currently iterates over all paragraphs of an open buffer to find new and updated macro templates. Why not move all the logic of resolving macros, shifting around arguments there?

It's inside of the buffer class, hence it has all the information needed to build a local macro table. Moreover it has a global view on the buffer such that it would be possible to handle \renewcommand and to handle the order of macro definitions correctly.

• Problem: The iteration of Buffer::buildMacros only sees the toplevel insets of the paragraphs, but for example not the InsetMathMacro objects. Stefan?
• Solution 1: Buffer::buildMacros can be changed to use DocIterator instead.
• Solution 2: a new macro could "register" itself in the Buffer. This way, Buffer always have access to an up to data macro table. This solution avoids the full document parsing problem of solution 1.
• Inset have no connection to the buffer at the moment. They do not even know when the buffer goes away. With solution 2 the buffer also has to make the macro unregister when closing. Somehow such a registration system contradicts the current design. Maybe just my taste Stefan?
• Solution 3: We could keep my approach in the previous proposal above, that macros still are updated from MathArray. During metric calculation we would have to provide a paragraph number. So the MathArray/InsetMathMacro could ask the buffer for the right MacroData which is valid at the point in the document. Stefan?
• Question: Is there an more elegant way to get the paragraph number to the inset metric routine than this one: Buffer::buildMacros looks for macro definitions and assigns paragraph numbers to the paragraphs. BufferView::updateMetrics (that's where the buildMacro came from) is the only place where metric recalculations of paragraphs are issued (is this right?). So updateMetrics (or whatever is calling the insets metrics method finally) should set pass along the paragraph number (possibly in the MetricsInfo structure). MathArray::metrics and InsetMathMacro then can use this to query the buffer about the right MacroData. Sounds reasonable. Stefan?
• Have a running implementation of this approach now. See the Xs in the use cases above Stefan?

#### D) Stefan: combination of C) and D)

1. Buffer::updateMacros looks for macro definitions and stores them in a sorted table with the paragraph number. The table is updated before all the metrics calculation
2. During the Inset::metrics traversal a temporal macro table is built up for the current paragraph (tracking also the macros definitions in the same paragraph), pointing back to the table from 1.
3. In MathData::metrics macros are updated. This includes moving out and in arguments, and the folding/unfolding of macros.
4. In MathMacro::metrics the macro definition is looked up in the table of 2 and the visual representation is created.
• View/Fold Macro
• View/Unfold Macro
• Edit/Math/Macro Definition/Append Paramter
• Edit/Math/Macro Definition/Remove last Paramter
• Edit/Math/Macro Definition/Toggle Optional Paramter
• Edit/Math/Macro Definition/Insert Optional Paramter
• Edit/Math/Macro Definition/Remove Optional Parameter
• Edit/Math/Macro Definition/Append Parameter Eating from the Right
• Edit/Math/Macro Definition/Append Optional Parameter Eating from the Right
• Edit/Math/Macro Definition/Remove Parameter Spitting Out to the Right
##### Problems/Questions/Issues
• Higher order substition possible somehow?
• Shifting takes place in MathData::metrics which is a const method. But Shifting is fundamentally non-const
• Extra traversal of the formula tree for shifting? Overhead?
##### Documentation

A LyX file documenting the implementation, the file format and the user commands is here: dynmacro.lyx (PDF)

### Testcases

 \newcommand{\foo}[1]{(#1)}
\newcommand{\baa}[1]{[#1]}


Correct interpretations are:

 \baa\foo{1} -> [(])1
{\foo} -> ! Argument of \foo has an extra }.
\baa{\foo{1}} -> [(1)]
\foo linefeed -> ( linefeed )
\foo a^1 -> (a)^1
\foo{\sum a}^1 -> (\sum a)^1 with the 1 vertically aligned at the ), not the height of the sum
\foo^ -> "(" with a superscript ")"