forked from aniani/vim
patch 9.0.1001: classes are not documented or implemented yet
Problem: Classes are not documented or implemented yet. Solution: Make the first steps at documenting Vim9 objects, classes and interfaces. Make initial choices for the syntax. Add a skeleton implementation. Add "public" and "this" in the command table.
This commit is contained in:
parent
b21b8e9ed0
commit
c1c365c1ca
2
Filelist
2
Filelist
@ -163,6 +163,7 @@ SRC_ALL = \
|
|||||||
src/version.h \
|
src/version.h \
|
||||||
src/vim.h \
|
src/vim.h \
|
||||||
src/vim9.h \
|
src/vim9.h \
|
||||||
|
src/vim9class.c \
|
||||||
src/vim9cmds.c \
|
src/vim9cmds.c \
|
||||||
src/vim9compile.c \
|
src/vim9compile.c \
|
||||||
src/vim9execute.c \
|
src/vim9execute.c \
|
||||||
@ -327,6 +328,7 @@ SRC_ALL = \
|
|||||||
src/proto/usercmd.pro \
|
src/proto/usercmd.pro \
|
||||||
src/proto/userfunc.pro \
|
src/proto/userfunc.pro \
|
||||||
src/proto/version.pro \
|
src/proto/version.pro \
|
||||||
|
src/proto/vim9class.pro \
|
||||||
src/proto/vim9cmds.pro \
|
src/proto/vim9cmds.pro \
|
||||||
src/proto/vim9compile.pro \
|
src/proto/vim9compile.pro \
|
||||||
src/proto/vim9execute.pro \
|
src/proto/vim9execute.pro \
|
||||||
|
@ -161,6 +161,7 @@ DOCS = \
|
|||||||
version9.txt \
|
version9.txt \
|
||||||
vi_diff.txt \
|
vi_diff.txt \
|
||||||
vim9.txt \
|
vim9.txt \
|
||||||
|
vim9class.txt \
|
||||||
visual.txt \
|
visual.txt \
|
||||||
windows.txt \
|
windows.txt \
|
||||||
workshop.txt
|
workshop.txt
|
||||||
@ -313,6 +314,7 @@ HTMLS = \
|
|||||||
vi_diff.html \
|
vi_diff.html \
|
||||||
vimindex.html \
|
vimindex.html \
|
||||||
vim9.html \
|
vim9.html \
|
||||||
|
vim9class.html \
|
||||||
visual.html \
|
visual.html \
|
||||||
windows.html \
|
windows.html \
|
||||||
workshop.html
|
workshop.html
|
||||||
|
@ -16,7 +16,7 @@ features in Vim9 script.
|
|||||||
3. New style functions |fast-functions|
|
3. New style functions |fast-functions|
|
||||||
4. Types |vim9-types|
|
4. Types |vim9-types|
|
||||||
5. Namespace, Import and Export |vim9script|
|
5. Namespace, Import and Export |vim9script|
|
||||||
6. Future work: classes |vim9-classes|
|
6. Classes and interfaces |vim9-classes|
|
||||||
|
|
||||||
9. Rationale |vim9-rationale|
|
9. Rationale |vim9-rationale|
|
||||||
|
|
||||||
@ -1940,73 +1940,17 @@ Or: >
|
|||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
||||||
6. Future work: classes *vim9-classes*
|
6. Classes and interfaces *vim9-classes*
|
||||||
|
|
||||||
Above "class" was mentioned a few times, but it has not been implemented yet.
|
In legacy script a Dictionary could be used as a kind-of object, by adding
|
||||||
Most of Vim9 script can be created without this functionality, and since
|
members that are functions. However, this is quite inefficient and requires
|
||||||
implementing classes is going to be a lot of work, it is left for the future.
|
the writer to do the work of making sure all the objects have the right
|
||||||
For now we'll just make sure classes can be added later.
|
members. See |Dictionary-function|.
|
||||||
|
|
||||||
Thoughts:
|
In |Vim9| script you can have classes, objects and interfaces like in most
|
||||||
- `class` / `endclass`, the whole class must be in one file
|
popular object-oriented programming languages. Since this is a lot of
|
||||||
- Class names are always CamelCase (to avoid a name clash with builtin types)
|
functionality it is located in a separate help file: |vim9class.txt|.
|
||||||
- A single constructor called "constructor" (similar to TypeScript)
|
|
||||||
- Single inheritance: `class ThisClass extends BaseClass`
|
|
||||||
- `interface` / `endinterface` (looks like a class without any implementation)
|
|
||||||
- Explicit declaration that the class supports an interface, so that type
|
|
||||||
checking works properly:
|
|
||||||
`class SomeClass implements SomeInterface, OtherInterface`
|
|
||||||
- `abstract class` (class with incomplete implementation) - not really needed?
|
|
||||||
- Class (static) methods and Object methods: syntax to be defined.
|
|
||||||
- Class (static) members and Object members: syntax to be defined.
|
|
||||||
- Access control: private / protected / shared / public ? Keep it simple.
|
|
||||||
- Access object members with `this.member` ?
|
|
||||||
- Generics for class: `class <Tkey, Tentry>`
|
|
||||||
- Generics for function: `def <Tkey> GetLast(key: Tkey)`
|
|
||||||
- Method overloading (two methods with the same name but different argument
|
|
||||||
types): Most likely not
|
|
||||||
- Mixins: not sure if that is useful, leave out for simplicity.
|
|
||||||
|
|
||||||
Again, much of this is from TypeScript with a slightly different syntax.
|
|
||||||
|
|
||||||
Some things that look like good additions:
|
|
||||||
- Use a class as an interface (like Dart)
|
|
||||||
- Extend a class with methods, using an import (like Dart)
|
|
||||||
- Mixins
|
|
||||||
- For testing: Mock mechanism
|
|
||||||
|
|
||||||
An important class that will be provided is "Promise". Since Vim is single
|
|
||||||
threaded, connecting asynchronous operations is a natural way of allowing
|
|
||||||
plugins to do their work without blocking the user. It's a uniform way to
|
|
||||||
invoke callbacks and handle timeouts and errors.
|
|
||||||
|
|
||||||
Some commands have already been reserved:
|
|
||||||
*:class*
|
|
||||||
*:endclass*
|
|
||||||
*:abstract*
|
|
||||||
*:enum*
|
|
||||||
*:endenum*
|
|
||||||
*:interface*
|
|
||||||
*:endinterface*
|
|
||||||
*:static*
|
|
||||||
*:type*
|
|
||||||
|
|
||||||
Some examples: >
|
|
||||||
|
|
||||||
abstract class Person
|
|
||||||
static const prefix = 'xxx'
|
|
||||||
var name: string
|
|
||||||
|
|
||||||
def constructor(name: string)
|
|
||||||
this.name = name
|
|
||||||
enddef
|
|
||||||
|
|
||||||
def display(): void
|
|
||||||
echo name
|
|
||||||
enddef
|
|
||||||
|
|
||||||
abstract def find(string): Person
|
|
||||||
endclass
|
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
||||||
@ -2293,18 +2237,5 @@ tool need to be supported. Since most languages support classes the lack of
|
|||||||
support for classes in Vim is then a problem.
|
support for classes in Vim is then a problem.
|
||||||
|
|
||||||
|
|
||||||
Classes ~
|
|
||||||
|
|
||||||
Vim supports a kind-of object oriented programming by adding methods to a
|
|
||||||
dictionary. With some care this can be made to work, but it does not look
|
|
||||||
like real classes. On top of that, it's quite slow, because of the use of
|
|
||||||
dictionaries.
|
|
||||||
|
|
||||||
It would be good to support real classes, and this is planned for a later
|
|
||||||
version. The support is a "minimal common functionality" of class support in
|
|
||||||
most languages. It will work much like Java, which is the most popular
|
|
||||||
programming language.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||||
|
697
runtime/doc/vim9class.txt
Normal file
697
runtime/doc/vim9class.txt
Normal file
@ -0,0 +1,697 @@
|
|||||||
|
*vim9class.txt* For Vim version 9.0. Last change: 2022 Dec 04
|
||||||
|
|
||||||
|
|
||||||
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
|
|
||||||
|
|
||||||
|
NOTE - This is under development, anything can still change! - NOTE
|
||||||
|
|
||||||
|
|
||||||
|
Vim9 classes, objects, interfaces, types and enums.
|
||||||
|
|
||||||
|
1. Overview |Vim9-class-overview|
|
||||||
|
2. A simple class |Vim9-simple-class|
|
||||||
|
3. Using an abstract class |Vim9-abstract-class|
|
||||||
|
4. Using an interface |Vim9-using-interface|
|
||||||
|
5. More class details |Vim9-class|
|
||||||
|
6. Type definition |Vim9-type|
|
||||||
|
7. Enum |Vim9-enum|
|
||||||
|
|
||||||
|
9. Rationale
|
||||||
|
10. To be done later
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
1. Overview *Vim9-class-overview*
|
||||||
|
|
||||||
|
The fancy term is "object-oriented programming". You can find lots of study
|
||||||
|
material about this subject. Here we document what |Vim9| script provides,
|
||||||
|
assuming you know the basics already. Added are helpful hints about how
|
||||||
|
to use this functionality effectively.
|
||||||
|
|
||||||
|
The basic item is an object:
|
||||||
|
- An object stores state. It contains one or more variables that can each
|
||||||
|
have a value.
|
||||||
|
- An object usually provides functions that manipulate its state. These
|
||||||
|
functions are invoked "on the object", which is what sets it apart from the
|
||||||
|
traditional separation of data and code that manipulates the data.
|
||||||
|
- An object has a well defined interface, with typed member variables and
|
||||||
|
member functions.
|
||||||
|
- Objects are created by a class and all objects have the same interface.
|
||||||
|
This never changes, it is not dynamic.
|
||||||
|
|
||||||
|
An object can only be created by a class. A class provides:
|
||||||
|
- A new() method, the constructor, which returns an object for the class.
|
||||||
|
This method is invoked on the class name: MyClass.new().
|
||||||
|
- State shared by all objects of the class: class variables and constants.
|
||||||
|
- A hierarchy of classes, with super-classes and sub-classes, inheritance.
|
||||||
|
|
||||||
|
An interface is used to specify properties of an object:
|
||||||
|
- An object can declare several interfaces that it implements.
|
||||||
|
- Different objects implementing the same interface can be used the same way.
|
||||||
|
|
||||||
|
The class hierarchy allows for single inheritance. Otherwise interfaces are
|
||||||
|
to be used where needed.
|
||||||
|
|
||||||
|
|
||||||
|
Class modeling ~
|
||||||
|
|
||||||
|
You can model classes any way you like. Keep in mind what you are building,
|
||||||
|
don't try to model the real world. This can be confusing, especially because
|
||||||
|
teachers use real-world objects to explain class relations and you might think
|
||||||
|
your model should therefore reflect the real world. It doesn't! The model
|
||||||
|
should match your purpose.
|
||||||
|
|
||||||
|
You will soon find that composition is often better than inheritance. Don't
|
||||||
|
waste time trying to find the optimal class model. Or waste time discussing
|
||||||
|
whether a square is a rectangle or that a rectangle is a square. It doesn't
|
||||||
|
matter.
|
||||||
|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
2. A simple class *Vim9-simple-class*
|
||||||
|
|
||||||
|
Let's start with a simple example: a class that stores a text position: >
|
||||||
|
|
||||||
|
class TextPosition
|
||||||
|
this.lnum: number
|
||||||
|
this.col: number
|
||||||
|
|
||||||
|
def new(lnum: number, col: number)
|
||||||
|
this.lnum = lnum
|
||||||
|
this.col = col
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def SetLnum(lnum: number)
|
||||||
|
this.lnum = lnum
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def SetCol(col: number)
|
||||||
|
this.col = col
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def SetPosition(lnum: number, col: number)
|
||||||
|
this.lnum = lnum
|
||||||
|
this.col = col
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
You can create an object from this class with the new() method: >
|
||||||
|
|
||||||
|
var pos = TextPosition.new(1, 1)
|
||||||
|
|
||||||
|
The object members "lnum" and "col" can be accessed directly: >
|
||||||
|
|
||||||
|
echo $'The text position is ({pos.lnum}, {pos.col})'
|
||||||
|
|
||||||
|
If you have been using other object-oriented languages you will notice that
|
||||||
|
in Vim the object members are consistently referred to with the "this."
|
||||||
|
prefix. This is different from languages like Java and TypeScript. This
|
||||||
|
naming convention makes the object members easy to spot. Also, when a
|
||||||
|
variable does not have the "this." prefix you know it is not an object member.
|
||||||
|
|
||||||
|
|
||||||
|
Member write access ~
|
||||||
|
|
||||||
|
Now try to change an object member directly: >
|
||||||
|
|
||||||
|
pos.lnum = 9
|
||||||
|
|
||||||
|
This will give you an error! That is because by default object members can be
|
||||||
|
read but not set. That's why the class provides a method for it: >
|
||||||
|
|
||||||
|
pos.SetLnum(9)
|
||||||
|
|
||||||
|
Allowing to read but not set an object member is the most common and safest
|
||||||
|
way. Most often there is no problem using a value, while setting a value may
|
||||||
|
have side effects that need to be taken care of. In this case, the SetLnum()
|
||||||
|
method could check if the line number is valid and either give an error or use
|
||||||
|
the closest valid value.
|
||||||
|
|
||||||
|
If you don't care about side effects and want to allow the object member to be
|
||||||
|
changed at any time, you can make it public: >
|
||||||
|
|
||||||
|
public this.lnum: number
|
||||||
|
public this.col number
|
||||||
|
|
||||||
|
Now you don't need the SetLnum(), SetCol() and SetPosition() methods, setting
|
||||||
|
"pos.lnum" directly above will no longer give an error.
|
||||||
|
|
||||||
|
|
||||||
|
Private members ~
|
||||||
|
|
||||||
|
On the other hand, if you do not want the object members to be read directly,
|
||||||
|
you can make them private. This is done by prefixing an underscore to the
|
||||||
|
name: >
|
||||||
|
|
||||||
|
this._lnum: number
|
||||||
|
this._col number
|
||||||
|
|
||||||
|
Now you need to provide methods to get the value of the private members.
|
||||||
|
These are commonly call getters. We recommend using a name that starts with
|
||||||
|
"Get": >
|
||||||
|
|
||||||
|
def GetLnum(): number
|
||||||
|
return this._lnum
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def GetCol() number
|
||||||
|
return this._col
|
||||||
|
enddef
|
||||||
|
|
||||||
|
This example isn't very useful, the members might as well have been public.
|
||||||
|
It does become useful if you check the value. For example, restrict the line
|
||||||
|
number to the total number of lines: >
|
||||||
|
|
||||||
|
def GetLnum(): number
|
||||||
|
if this._lnum > this._lineCount
|
||||||
|
return this._lineCount
|
||||||
|
endif
|
||||||
|
return this._lnum
|
||||||
|
enddef
|
||||||
|
|
||||||
|
|
||||||
|
Simplifying the new() method ~
|
||||||
|
|
||||||
|
Many constructors take values for the object members. Thus you very often see
|
||||||
|
this pattern: >
|
||||||
|
|
||||||
|
this.lnum: number
|
||||||
|
this.col: number
|
||||||
|
|
||||||
|
def new(lnum: number, col: number)
|
||||||
|
this.lnum = lnum
|
||||||
|
this.col = col
|
||||||
|
enddef
|
||||||
|
|
||||||
|
Not only is this text you need to write, it also has the type of each member
|
||||||
|
twice. Since this is so common a shorter way to write new() is provided: >
|
||||||
|
|
||||||
|
def new(this.lnum, this.col)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
The semantics are easy to understand: Providing the object member name,
|
||||||
|
including "this.", as the argument to new() means the value provided in the
|
||||||
|
new() call is assigned to that object member. This mechanism is coming from
|
||||||
|
the Dart language.
|
||||||
|
|
||||||
|
The sequence of constructing a new object is:
|
||||||
|
1. Memory is allocated and cleared. All values are zero/false/empty.
|
||||||
|
2. For each declared member that has an initializer, the expression is
|
||||||
|
evaluated and assigned to the member. This happens in the sequence the
|
||||||
|
members are declared in the class.
|
||||||
|
3. Arguments in the new() method in the "this.name" form are assigned.
|
||||||
|
4. The body of the new() method is executed.
|
||||||
|
|
||||||
|
TODO: for a sub-class the constructor of the parent class will be invoked
|
||||||
|
somewhere.
|
||||||
|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
3. Using an abstract class *Vim9-abstract-class*
|
||||||
|
|
||||||
|
An abstract class forms the base for at least one sub-class. In the class
|
||||||
|
model one often finds that a few classes have the same properties that can be
|
||||||
|
shared, but a class with those properties does not have enough state to create
|
||||||
|
an object from. A sub-class must extend the abstract class and add the
|
||||||
|
missing state and/or methods before it can be used to create objects for.
|
||||||
|
|
||||||
|
An abstract class does not have a new() method.
|
||||||
|
|
||||||
|
For example, a Shape class could store a color and thickness. You cannot
|
||||||
|
create a Shape object, it is missing the information about what kind of shape
|
||||||
|
it is. The Shape class functions as the base for a Square and a Triangle
|
||||||
|
class, for which objects can be created. Example: >
|
||||||
|
|
||||||
|
abstract class Shape
|
||||||
|
this.color = Color.Black
|
||||||
|
this.thickness = 10
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Square extends Shape
|
||||||
|
this.size: number
|
||||||
|
|
||||||
|
def new(this.size)
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Triangle extends Shape
|
||||||
|
this.base: number
|
||||||
|
this.height: number
|
||||||
|
|
||||||
|
def new(this.base, this.height)
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
<
|
||||||
|
*class-member* *:static*
|
||||||
|
Class members are declared with "static". They are used by the name without a
|
||||||
|
prefix: >
|
||||||
|
|
||||||
|
class OtherThing
|
||||||
|
this.size: number
|
||||||
|
static totalSize: number
|
||||||
|
|
||||||
|
def new(this.size)
|
||||||
|
totalSize += this.size
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
<
|
||||||
|
*class-method*
|
||||||
|
Class methods are also declared with "static". They have no access to object
|
||||||
|
members, they cannot use the "this" keyword. >
|
||||||
|
|
||||||
|
class OtherThing
|
||||||
|
this.size: number
|
||||||
|
static totalSize: number
|
||||||
|
|
||||||
|
" Clear the total size and return the value it had before.
|
||||||
|
static def ClearTotalSize(): number
|
||||||
|
var prev = totalSize
|
||||||
|
totalSize = 0
|
||||||
|
return prev
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
4. Using an interface *Vim9-using-interface*
|
||||||
|
|
||||||
|
The example above with Shape, Square and Triangle can be made more useful if
|
||||||
|
we add a method to compute the surface of the object. For that we create the
|
||||||
|
interface called HasSurface, which specifies one method Surface() that returns
|
||||||
|
a number. This example extends the one above: >
|
||||||
|
|
||||||
|
abstract class Shape
|
||||||
|
this.color = Color.Black
|
||||||
|
this.thickness = 10
|
||||||
|
endclass
|
||||||
|
|
||||||
|
interface HasSurface
|
||||||
|
def Surface(): number
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
class Square extends Shape implements HasSurface
|
||||||
|
this.size: number
|
||||||
|
|
||||||
|
def new(this.size)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Surface(): number
|
||||||
|
return this.size * this.size
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Triangle extends Shape implements HasSurface
|
||||||
|
this.base: number
|
||||||
|
this.height: number
|
||||||
|
|
||||||
|
def new(this.base, this.height)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Surface(): number
|
||||||
|
return this.base * this.height / 2
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
The interface name can be used as a type: >
|
||||||
|
|
||||||
|
var shapes: list<HasSurface> = [
|
||||||
|
Square.new(12),
|
||||||
|
Triangle.new(8, 15),
|
||||||
|
]
|
||||||
|
for shape in shapes
|
||||||
|
echo $'the surface is {shape.Surface()}'
|
||||||
|
endfor
|
||||||
|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
5. More class details *Vim9-class*
|
||||||
|
|
||||||
|
Defining a class ~
|
||||||
|
*:class* *:endclass* *:abstract*
|
||||||
|
A class is defined between `:class` and `:endclass`. The whole class is
|
||||||
|
defined in one script file. It is not possible to add to a class later.
|
||||||
|
|
||||||
|
It is possible to define more than one class in a script file. Although it
|
||||||
|
usually is better to export only one main class. It can be useful to define
|
||||||
|
types, enums and helper classes though.
|
||||||
|
|
||||||
|
The `:abstract` keyword may be prefixed and `:export` may be used. That gives
|
||||||
|
these variants: >
|
||||||
|
|
||||||
|
class ClassName
|
||||||
|
endclass
|
||||||
|
|
||||||
|
export class ClassName
|
||||||
|
endclass
|
||||||
|
|
||||||
|
abstract class ClassName
|
||||||
|
endclass
|
||||||
|
|
||||||
|
export abstract class ClassName
|
||||||
|
endclass
|
||||||
|
<
|
||||||
|
*E1314*
|
||||||
|
The class name should be CamelCased. It must start with an uppercase letter.
|
||||||
|
That avoids clashing with builtin types.
|
||||||
|
|
||||||
|
After the class name these optional items can be used. Each can appear only
|
||||||
|
once. They can appear in any order, although this order is recommended: >
|
||||||
|
extends ClassName
|
||||||
|
implements InterfaceName, OtherInterface
|
||||||
|
specifies SomeInterface
|
||||||
|
< *extends*
|
||||||
|
A class can extend one other class.
|
||||||
|
*implements*
|
||||||
|
A class can implement one or more interfaces.
|
||||||
|
*specifies*
|
||||||
|
A class can declare it's interface, the object members and methods, with a
|
||||||
|
named interface. This avoids the need for separately specifying the
|
||||||
|
interface, which is often done an many languages, especially Java.
|
||||||
|
|
||||||
|
|
||||||
|
Defining an interface ~
|
||||||
|
*:interface* *:endinterface*
|
||||||
|
An interface is defined between `:interface` and `:endinterface`. It may be
|
||||||
|
prefixed with `:export`: >
|
||||||
|
|
||||||
|
interface InterfaceName
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
export interface InterfaceName
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
An interface can declare object members, just like in a class but without any
|
||||||
|
initializer.
|
||||||
|
|
||||||
|
An interface can declare methods with `:def`, including the arguments and
|
||||||
|
return type, but without the body and without `:enddef`. Example: >
|
||||||
|
|
||||||
|
interface HasSurface
|
||||||
|
this.size: number
|
||||||
|
def Surface(): number
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
The "Has" prefix can be used to make it easier to guess this is an interface
|
||||||
|
name, with a hint about what it provides.
|
||||||
|
|
||||||
|
|
||||||
|
Default constructor ~
|
||||||
|
|
||||||
|
In case you define a class without a new() method, one will be automatically
|
||||||
|
defined. This default constructor will have arguments for all the object
|
||||||
|
members, in the order they were specified. Thus if your class looks like: >
|
||||||
|
|
||||||
|
class AutoNew
|
||||||
|
this.name: string
|
||||||
|
this.age: number
|
||||||
|
this.gender: Gender
|
||||||
|
endclass
|
||||||
|
|
||||||
|
Then The default constructor will be: >
|
||||||
|
|
||||||
|
def new(this.name, this.age, this.gender)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
All object members will be used, also private access ones.
|
||||||
|
|
||||||
|
|
||||||
|
Multiple constructors ~
|
||||||
|
|
||||||
|
Normally a class has just one new() constructor. In case you find that the
|
||||||
|
constructor is often called with the same arguments you may want to simplify
|
||||||
|
your code by putting those arguments into a second constructor method. For
|
||||||
|
example, if you tend to use the color black a lot: >
|
||||||
|
|
||||||
|
def new(this.garment, this.color, this.size)
|
||||||
|
enddef
|
||||||
|
...
|
||||||
|
var pants = new(Garment.pants, Color.black, "XL")
|
||||||
|
var shirt = new(Garment.shirt, Color.black, "XL")
|
||||||
|
var shoes = new(Garment.shoes, Color.black, "45")
|
||||||
|
|
||||||
|
Instead of repeating the color every time you can add a constructor that
|
||||||
|
includes it: >
|
||||||
|
|
||||||
|
def newBlack(this.garment, this.size)
|
||||||
|
this.color = Color.black
|
||||||
|
enddef
|
||||||
|
...
|
||||||
|
var pants = newBlack(Garment.pants, "XL")
|
||||||
|
var shirt = newBlack(Garment.shirt, "XL")
|
||||||
|
var shoes = newBlack(Garment.shoes, "9.5")
|
||||||
|
|
||||||
|
Note that the method name must start with "new". If there is no method called
|
||||||
|
"new()" then the default constructor is added, even though there are other
|
||||||
|
constructor methods.
|
||||||
|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
6. Type definition *Vim9-type* *:type*
|
||||||
|
|
||||||
|
A type definition is giving a name to a type specification. For Example: >
|
||||||
|
|
||||||
|
:type ListOfStrings list<string>
|
||||||
|
|
||||||
|
TODO: more explanation
|
||||||
|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
7. Enum *Vim9-enum* *:enum* *:endenum*
|
||||||
|
|
||||||
|
An enum is a type that can have one of a list of values. Example: >
|
||||||
|
|
||||||
|
:enum Color
|
||||||
|
White
|
||||||
|
Red
|
||||||
|
Green
|
||||||
|
Blue
|
||||||
|
Black
|
||||||
|
:endenum
|
||||||
|
|
||||||
|
TODO: more explanation
|
||||||
|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
9. Rationale
|
||||||
|
|
||||||
|
Most of the choices for |Vim9| classes come from popular and recently
|
||||||
|
developed languages, such as Java, TypeScript and Dart. The syntax has been
|
||||||
|
made to fit with the way Vim script works, such as using `endclass` instead of
|
||||||
|
using curly braces around the whole class.
|
||||||
|
|
||||||
|
Some common constructs of object-oriented languages were chosen very long ago
|
||||||
|
when this kind of programming was still new, and later found to be
|
||||||
|
sub-optimal. By this time those constructs were widely used and changing them
|
||||||
|
was not an option. In Vim we do have the freedom to make different choices,
|
||||||
|
since classes are completely new. We can make the syntax simpler and more
|
||||||
|
consistent than what "old" languages use. Without diverting too much, it
|
||||||
|
should still mostly look like what you know from existing languages.
|
||||||
|
|
||||||
|
Some recently developed languages add all kinds of fancy features that we
|
||||||
|
don't need for Vim. But some have nice ideas that we do want to use.
|
||||||
|
Thus we end up with a base of what is common in popular languages, dropping
|
||||||
|
what looks like a bad idea, and adding some nice features that are easy to
|
||||||
|
understand.
|
||||||
|
|
||||||
|
The main rules we use to make decisions:
|
||||||
|
- Keep it simple.
|
||||||
|
- No surprises, mostly do what other languages are doing.
|
||||||
|
- Avoid mistakes from the past.
|
||||||
|
- Avoid the need for the script writer to consult the help to understand how
|
||||||
|
things work, most things should be obvious.
|
||||||
|
- Keep it consistent.
|
||||||
|
- Aim at an average size plugin, not at a huge project.
|
||||||
|
|
||||||
|
|
||||||
|
Using new() for the constructor ~
|
||||||
|
|
||||||
|
Many languages use the class name for the constructor method. A disadvantage
|
||||||
|
is that quite often this is a long name. And when changing the class name all
|
||||||
|
constructor methods need to be renamed. Not a big deal, but still a
|
||||||
|
disadvantage.
|
||||||
|
|
||||||
|
Other languages, such as TypeScript, use a specific name, such as
|
||||||
|
"constructor()". That seems better. However, using "new" or "new()" to
|
||||||
|
create a new object has no obvious relation with "constructor()".
|
||||||
|
|
||||||
|
For |Vim9| script using the same method name for all constructors seemed like
|
||||||
|
the right choice, and by calling it new() the relation between the caller and
|
||||||
|
the method being called is obvious.
|
||||||
|
|
||||||
|
|
||||||
|
No overloading of the constructor ~
|
||||||
|
|
||||||
|
In Vim script, both legacy and |Vim9| script, there is no overloading of
|
||||||
|
functions. That means it is not possible to use the same function name with
|
||||||
|
different types of arguments. Therefore there also is only one new()
|
||||||
|
constructor.
|
||||||
|
|
||||||
|
With |Vim9| script it would be possible to support overloading, since
|
||||||
|
arguments are typed. However, this gets complicated very quickly. Looking at
|
||||||
|
a new() call one has to inspect the types of the arguments to know which of
|
||||||
|
several new() methods is actually being called. And that can require
|
||||||
|
inspecting quite a bit of code. For example, if one of the arguments is the
|
||||||
|
return value of a method, you need to find that method to see what type it is
|
||||||
|
returning.
|
||||||
|
|
||||||
|
Instead, every constructor has to have a different name, starting with "new".
|
||||||
|
That way multiple constructors with different arguments are possible, while it
|
||||||
|
is very easy to see which constructor is being used. And the type of
|
||||||
|
arguments can be properly checked.
|
||||||
|
|
||||||
|
|
||||||
|
No overloading of methods ~
|
||||||
|
|
||||||
|
Same reasoning as for the constructor: It is often not obvious what type
|
||||||
|
arguments have, which would make it difficult to figure out what method is
|
||||||
|
actually being called. Better just give the methods a different name, then
|
||||||
|
type checking will make sure it works as you intended. This rules out
|
||||||
|
polymorphism, which we don't really need anyway.
|
||||||
|
|
||||||
|
|
||||||
|
Using "this.member" everywhere ~
|
||||||
|
|
||||||
|
The object members in various programming languages can often be accessed in
|
||||||
|
different ways, depending on the location. Sometimes "this." has to be
|
||||||
|
prepended to avoid ambiguity. They are usually declared without "this.".
|
||||||
|
That is quite inconsistent and sometimes confusing.
|
||||||
|
|
||||||
|
A very common issue is that in the constructor the arguments use the same name
|
||||||
|
as the object member. Then for these members "this." needs to be prefixed in
|
||||||
|
the body, while for other members this is not needed and often omitted. This
|
||||||
|
leads to a mix of members with and without "this.", which is inconsistent.
|
||||||
|
|
||||||
|
For |Vim9| classes the "this." prefix is always used. Also for declaring the
|
||||||
|
members. Simple and consistent. When looking at the code inside a class it's
|
||||||
|
also directly clear which variable references are object members and which
|
||||||
|
aren't.
|
||||||
|
|
||||||
|
|
||||||
|
Single inheritance and interfaces ~
|
||||||
|
|
||||||
|
Some languages support multiple inheritance. Although that can be useful in
|
||||||
|
some cases, it makes the rules of how a class works quite complicated.
|
||||||
|
Instead, using interfaces to declare what is supported is much simpler. The
|
||||||
|
very popular Java language does it this way, and it should be good enough for
|
||||||
|
Vim. The "keep it simple" rule applies here.
|
||||||
|
|
||||||
|
Explicitly declaring that a class supports an interface makes it easy to see
|
||||||
|
what a class is intended for. It also makes it possible to do proper type
|
||||||
|
checking. When an interface is changed any class that declares to implement
|
||||||
|
it will be checked if that change was also changed. The mechanism to assume a
|
||||||
|
class implements an interface just because the methods happen to match is
|
||||||
|
brittle and leads to obscure problems, let's not do that.
|
||||||
|
|
||||||
|
|
||||||
|
Using class members ~
|
||||||
|
|
||||||
|
Using "static member" to declare a class member is very common, nothing new
|
||||||
|
here. In |Vim9| script these can be accessed directly by their name. Very
|
||||||
|
much like how a script-local variable can be used in a function. Since object
|
||||||
|
members are always accessed with "this." prepended, it's also quickly clear
|
||||||
|
what kind of member it is.
|
||||||
|
|
||||||
|
TypeScript prepends the class name before the class member, also inside the
|
||||||
|
class. This has two problems: The class name can be rather long, taking up
|
||||||
|
quite a bit of space, and when the class is renamed all these places need to
|
||||||
|
be changed too.
|
||||||
|
|
||||||
|
|
||||||
|
Using "ClassName.new()" to construct an object ~
|
||||||
|
|
||||||
|
Many languages use the "new" operator to create an object, which is actually
|
||||||
|
kind of strange, since the constructor is defined as a method with arguments,
|
||||||
|
not a command. TypeScript also has the "new" keyword, but the method is
|
||||||
|
called "constructor()", it is hard to see the relation between the two.
|
||||||
|
|
||||||
|
In |Vim9| script the constructor method is called new(), and it is invoked as
|
||||||
|
new(), simple and straightforward. Other languages use "new ClassName()",
|
||||||
|
while there is no ClassName() method, it's a method by another name in the
|
||||||
|
class called ClassName. Quite confusing.
|
||||||
|
|
||||||
|
|
||||||
|
Default read access to object members ~
|
||||||
|
|
||||||
|
Some users will remark that the access rules for object members are
|
||||||
|
asymmetric. Well, that is intentional. Changing a value is a very different
|
||||||
|
action than reading a value. The read operation has no side effects, it can
|
||||||
|
be done any number of times without affecting the object. Changing the value
|
||||||
|
can have many side effects, and even have a ripple effect, affecting other
|
||||||
|
objects.
|
||||||
|
|
||||||
|
When adding object members one usually doesn't think much about this, just get
|
||||||
|
the type right. And normally the values are set in the new() method.
|
||||||
|
Therefore defaulting to read access only "just works" in most cases. And when
|
||||||
|
directly writing you get an error, which makes you wonder if you actually want
|
||||||
|
to allow that. This helps writing code with fewer mistakes.
|
||||||
|
|
||||||
|
|
||||||
|
Making object membes private with an underscore ~
|
||||||
|
|
||||||
|
When an object member is private, it can only be read and changed inside the
|
||||||
|
class (and in sub-classes), then it cannot be used outside of the class.
|
||||||
|
Prepending an underscore is a simple way to make that visible. Various
|
||||||
|
programming languages have this as a recommendation.
|
||||||
|
|
||||||
|
In case you change your mind and want to make the object member accessible
|
||||||
|
outside of the class, you will have to remove the underscore everywhere.
|
||||||
|
Since the name only appears in the class (and sub-classes) they will be easy
|
||||||
|
to find and change.
|
||||||
|
|
||||||
|
The other way around is much harder: you can easily prepend an underscore to
|
||||||
|
the object member inside the class to make it private, but any usage elsewhere
|
||||||
|
you will have to track down and change. You may have to make it a "set"
|
||||||
|
method call. This reflects the real world problem that taking away access
|
||||||
|
requires work to be done for all places where that access exists.
|
||||||
|
|
||||||
|
An alternative would have been using the "private" keyword, just like "public"
|
||||||
|
changes the access in the other direction. Well, that's just to reduce the
|
||||||
|
number of keywords.
|
||||||
|
|
||||||
|
|
||||||
|
No protected object members ~
|
||||||
|
|
||||||
|
Some languages provide several ways to control access to object members. The
|
||||||
|
most known is "protected", and the meaning varies from language to language.
|
||||||
|
Others are "shared", "private" and even "friend".
|
||||||
|
|
||||||
|
These rules make life more difficult. That can be justified in projects where
|
||||||
|
many people work on the same, complex code where it is easy to make mistakes.
|
||||||
|
Especially when refactoring or other changes to the class model.
|
||||||
|
|
||||||
|
The Vim scripts are expected to be used in a plugin, with just one person or a
|
||||||
|
small team working on it. Complex rules then only make it more complicated,
|
||||||
|
the extra safety provide by the rules isn't really needed. Let's just keep it
|
||||||
|
simple and not specify access details.
|
||||||
|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
10. To be done later
|
||||||
|
|
||||||
|
Can a newSomething() constructor invoke another constructor? If yes, what are
|
||||||
|
the restrictions?
|
||||||
|
|
||||||
|
Thoughts:
|
||||||
|
- Generics for a class: `class <Tkey, Tentry>`
|
||||||
|
- Generics for a function: `def <Tkey> GetLast(key: Tkey)`
|
||||||
|
- Mixins: not sure if that is useful, leave out for simplicity.
|
||||||
|
|
||||||
|
Some things that look like good additions:
|
||||||
|
- For testing: Mock mechanism
|
||||||
|
|
||||||
|
An important class to be provided is "Promise". Since Vim is single
|
||||||
|
threaded, connecting asynchronous operations is a natural way of allowing
|
||||||
|
plugins to do their work without blocking the user. It's a uniform way to
|
||||||
|
invoke callbacks and handle timeouts and errors.
|
||||||
|
|
||||||
|
|
||||||
|
vim:tw=78:ts=8:noet:ft=help:norl:
|
@ -174,6 +174,7 @@ SRC += \
|
|||||||
userfunc.c \
|
userfunc.c \
|
||||||
version.c \
|
version.c \
|
||||||
viminfo.c \
|
viminfo.c \
|
||||||
|
vim9class.c \
|
||||||
vim9cmds.c \
|
vim9cmds.c \
|
||||||
vim9compile.c \
|
vim9compile.c \
|
||||||
vim9execute.c \
|
vim9execute.c \
|
||||||
|
@ -851,6 +851,7 @@ OBJ = \
|
|||||||
$(OUTDIR)/usercmd.o \
|
$(OUTDIR)/usercmd.o \
|
||||||
$(OUTDIR)/userfunc.o \
|
$(OUTDIR)/userfunc.o \
|
||||||
$(OUTDIR)/version.o \
|
$(OUTDIR)/version.o \
|
||||||
|
$(OUTDIR)/vim9class.o \
|
||||||
$(OUTDIR)/vim9cmds.o \
|
$(OUTDIR)/vim9cmds.o \
|
||||||
$(OUTDIR)/vim9compile.o \
|
$(OUTDIR)/vim9compile.o \
|
||||||
$(OUTDIR)/vim9execute.o \
|
$(OUTDIR)/vim9execute.o \
|
||||||
@ -1251,6 +1252,8 @@ $(OUTDIR)/netbeans.o: netbeans.c $(INCL) version.h
|
|||||||
|
|
||||||
$(OUTDIR)/version.o: version.c $(INCL) version.h
|
$(OUTDIR)/version.o: version.c $(INCL) version.h
|
||||||
|
|
||||||
|
$(OUTDIR)/vim9class.o: vim9class.c $(INCL) vim9.h
|
||||||
|
|
||||||
$(OUTDIR)/vim9cmds.o: vim9cmds.c $(INCL) vim9.h
|
$(OUTDIR)/vim9cmds.o: vim9cmds.c $(INCL) vim9.h
|
||||||
|
|
||||||
$(OUTDIR)/vim9compile.o: vim9compile.c $(INCL) vim9.h
|
$(OUTDIR)/vim9compile.o: vim9compile.c $(INCL) vim9.h
|
||||||
|
@ -735,6 +735,7 @@ OBJ = \
|
|||||||
$(OUTDIR)\undo.obj \
|
$(OUTDIR)\undo.obj \
|
||||||
$(OUTDIR)\usercmd.obj \
|
$(OUTDIR)\usercmd.obj \
|
||||||
$(OUTDIR)\userfunc.obj \
|
$(OUTDIR)\userfunc.obj \
|
||||||
|
$(OUTDIR)\vim9class.obj \
|
||||||
$(OUTDIR)\vim9cmds.obj \
|
$(OUTDIR)\vim9cmds.obj \
|
||||||
$(OUTDIR)\vim9compile.obj \
|
$(OUTDIR)\vim9compile.obj \
|
||||||
$(OUTDIR)\vim9execute.obj \
|
$(OUTDIR)\vim9execute.obj \
|
||||||
@ -1708,6 +1709,8 @@ $(OUTDIR)/userfunc.obj: $(OUTDIR) userfunc.c $(INCL)
|
|||||||
|
|
||||||
$(OUTDIR)/version.obj: $(OUTDIR) version.c $(INCL) version.h
|
$(OUTDIR)/version.obj: $(OUTDIR) version.c $(INCL) version.h
|
||||||
|
|
||||||
|
$(OUTDIR)/vim9class.obj: $(OUTDIR) vim9class.c $(INCL) vim9.h
|
||||||
|
|
||||||
$(OUTDIR)/vim9cmds.obj: $(OUTDIR) vim9cmds.c $(INCL) vim9.h
|
$(OUTDIR)/vim9cmds.obj: $(OUTDIR) vim9cmds.c $(INCL) vim9.h
|
||||||
|
|
||||||
$(OUTDIR)/vim9compile.obj: $(OUTDIR) vim9compile.c $(INCL) vim9.h
|
$(OUTDIR)/vim9compile.obj: $(OUTDIR) vim9compile.c $(INCL) vim9.h
|
||||||
@ -1915,6 +1918,7 @@ proto.h: \
|
|||||||
proto/undo.pro \
|
proto/undo.pro \
|
||||||
proto/usercmd.pro \
|
proto/usercmd.pro \
|
||||||
proto/userfunc.pro \
|
proto/userfunc.pro \
|
||||||
|
proto/vim9class.pro \
|
||||||
proto/vim9cmds.pro \
|
proto/vim9cmds.pro \
|
||||||
proto/vim9compile.pro \
|
proto/vim9compile.pro \
|
||||||
proto/vim9execute.pro \
|
proto/vim9execute.pro \
|
||||||
|
@ -409,6 +409,7 @@ SRC = \
|
|||||||
usercmd.c \
|
usercmd.c \
|
||||||
userfunc.c \
|
userfunc.c \
|
||||||
version.c \
|
version.c \
|
||||||
|
vim9class.c \
|
||||||
vim9cmds.c \
|
vim9cmds.c \
|
||||||
vim9compile.c \
|
vim9compile.c \
|
||||||
vim9execute.c \
|
vim9execute.c \
|
||||||
@ -534,6 +535,7 @@ OBJ = \
|
|||||||
usercmd.obj \
|
usercmd.obj \
|
||||||
userfunc.obj \
|
userfunc.obj \
|
||||||
version.obj \
|
version.obj \
|
||||||
|
vim9class.obj \
|
||||||
vim9cmds.obj \
|
vim9cmds.obj \
|
||||||
vim9compile.obj \
|
vim9compile.obj \
|
||||||
vim9execute.obj \
|
vim9execute.obj \
|
||||||
@ -1122,6 +1124,10 @@ viminfo.obj : viminfo.c vim.h [.auto]config.h feature.h os_unix.h \
|
|||||||
ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \
|
ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \
|
||||||
gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
|
gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
|
||||||
errors.h globals.h version.h
|
errors.h globals.h version.h
|
||||||
|
vim9class.obj : vim9class.c vim.h [.auto]config.h feature.h os_unix.h \
|
||||||
|
ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \
|
||||||
|
gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
|
||||||
|
errors.h globals.h version.h
|
||||||
vim9cmds.obj : vim9cmds.c vim.h [.auto]config.h feature.h os_unix.h \
|
vim9cmds.obj : vim9cmds.c vim.h [.auto]config.h feature.h os_unix.h \
|
||||||
ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \
|
ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \
|
||||||
gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
|
gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
|
||||||
|
11
src/Makefile
11
src/Makefile
@ -1584,6 +1584,7 @@ BASIC_SRC = \
|
|||||||
usercmd.c \
|
usercmd.c \
|
||||||
userfunc.c \
|
userfunc.c \
|
||||||
version.c \
|
version.c \
|
||||||
|
vim9class.c \
|
||||||
vim9cmds.c \
|
vim9cmds.c \
|
||||||
vim9compile.c \
|
vim9compile.c \
|
||||||
vim9execute.c \
|
vim9execute.c \
|
||||||
@ -1741,6 +1742,7 @@ OBJ_COMMON = \
|
|||||||
objects/usercmd.o \
|
objects/usercmd.o \
|
||||||
objects/userfunc.o \
|
objects/userfunc.o \
|
||||||
objects/version.o \
|
objects/version.o \
|
||||||
|
objects/vim9class.o \
|
||||||
objects/vim9cmds.o \
|
objects/vim9cmds.o \
|
||||||
objects/vim9compile.o \
|
objects/vim9compile.o \
|
||||||
objects/vim9execute.o \
|
objects/vim9execute.o \
|
||||||
@ -1931,6 +1933,7 @@ PRO_AUTO = \
|
|||||||
usercmd.pro \
|
usercmd.pro \
|
||||||
userfunc.pro \
|
userfunc.pro \
|
||||||
version.pro \
|
version.pro \
|
||||||
|
vim9class.pro \
|
||||||
vim9cmds.pro \
|
vim9cmds.pro \
|
||||||
vim9compile.pro \
|
vim9compile.pro \
|
||||||
vim9execute.pro \
|
vim9execute.pro \
|
||||||
@ -3489,6 +3492,9 @@ objects/usercmd.o: usercmd.c
|
|||||||
objects/userfunc.o: userfunc.c
|
objects/userfunc.o: userfunc.c
|
||||||
$(CCC) -o $@ userfunc.c
|
$(CCC) -o $@ userfunc.c
|
||||||
|
|
||||||
|
objects/vim9class.o: vim9class.c
|
||||||
|
$(CCC) -o $@ vim9class.c
|
||||||
|
|
||||||
objects/vim9cmds.o: vim9cmds.c
|
objects/vim9cmds.o: vim9cmds.c
|
||||||
$(CCC) -o $@ vim9cmds.c
|
$(CCC) -o $@ vim9cmds.c
|
||||||
|
|
||||||
@ -4168,6 +4174,11 @@ objects/version.o: version.c vim.h protodef.h auto/config.h feature.h os_unix.h
|
|||||||
proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \
|
proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \
|
||||||
libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \
|
libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \
|
||||||
globals.h errors.h version.h
|
globals.h errors.h version.h
|
||||||
|
objects/vim9class.o: vim9class.c vim.h protodef.h auto/config.h feature.h os_unix.h \
|
||||||
|
auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \
|
||||||
|
proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \
|
||||||
|
libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \
|
||||||
|
globals.h errors.h vim9.h
|
||||||
objects/vim9cmds.o: vim9cmds.c vim.h protodef.h auto/config.h feature.h os_unix.h \
|
objects/vim9cmds.o: vim9cmds.c vim.h protodef.h auto/config.h feature.h os_unix.h \
|
||||||
auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \
|
auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \
|
||||||
proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \
|
proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \
|
||||||
|
@ -3345,3 +3345,7 @@ EXTERN char e_not_allowed_to_change_window_layout_in_this_autocmd[]
|
|||||||
INIT(= N_("E1312: Not allowed to change the window layout in this autocmd"));
|
INIT(= N_("E1312: Not allowed to change the window layout in this autocmd"));
|
||||||
EXTERN char e_not_allowed_to_add_or_remove_entries_str[]
|
EXTERN char e_not_allowed_to_add_or_remove_entries_str[]
|
||||||
INIT(= N_("E1313: Not allowed to add or remove entries (%s)"));
|
INIT(= N_("E1313: Not allowed to add or remove entries (%s)"));
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
EXTERN char e_class_name_must_start_with_uppercase_letter_str[]
|
||||||
|
INIT(= N_("E1314: Class name must start with an uppercase letter: %s"));
|
||||||
|
#endif
|
||||||
|
@ -21,16 +21,16 @@ static const unsigned short cmdidxs1[26] =
|
|||||||
/* n */ 308,
|
/* n */ 308,
|
||||||
/* o */ 328,
|
/* o */ 328,
|
||||||
/* p */ 340,
|
/* p */ 340,
|
||||||
/* q */ 379,
|
/* q */ 380,
|
||||||
/* r */ 382,
|
/* r */ 383,
|
||||||
/* s */ 402,
|
/* s */ 403,
|
||||||
/* t */ 472,
|
/* t */ 473,
|
||||||
/* u */ 518,
|
/* u */ 520,
|
||||||
/* v */ 529,
|
/* v */ 531,
|
||||||
/* w */ 550,
|
/* w */ 552,
|
||||||
/* x */ 564,
|
/* x */ 566,
|
||||||
/* y */ 574,
|
/* y */ 576,
|
||||||
/* z */ 575
|
/* z */ 577
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -56,11 +56,11 @@ static const unsigned char cmdidxs2[26][26] =
|
|||||||
/* m */ { 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16 },
|
/* m */ { 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16 },
|
||||||
/* n */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 10, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0 },
|
/* n */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 10, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0 },
|
||||||
/* o */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 0, 9, 0, 11, 0, 0, 0 },
|
/* o */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 0, 9, 0, 11, 0, 0, 0 },
|
||||||
/* p */ { 1, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 0, 0, 16, 17, 26, 0, 27, 0, 28, 0 },
|
/* p */ { 1, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 0, 0, 16, 17, 26, 0, 28, 0, 29, 0 },
|
||||||
/* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
/* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
/* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 19, 0, 0, 0, 0 },
|
/* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 19, 0, 0, 0, 0 },
|
||||||
/* s */ { 2, 6, 15, 0, 19, 23, 0, 25, 26, 0, 0, 29, 31, 35, 39, 41, 0, 50, 0, 51, 0, 64, 65, 0, 66, 0 },
|
/* s */ { 2, 6, 15, 0, 19, 23, 0, 25, 26, 0, 0, 29, 31, 35, 39, 41, 0, 50, 0, 51, 0, 64, 65, 0, 66, 0 },
|
||||||
/* t */ { 2, 0, 19, 0, 24, 26, 0, 27, 0, 28, 0, 29, 33, 36, 38, 39, 0, 40, 42, 0, 43, 0, 0, 0, 45, 0 },
|
/* t */ { 2, 0, 19, 0, 24, 26, 0, 27, 0, 29, 0, 30, 34, 37, 39, 40, 0, 41, 43, 0, 44, 0, 0, 0, 46, 0 },
|
||||||
/* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
/* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
/* v */ { 1, 0, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 12, 15, 0, 0, 0, 0, 18, 0, 19, 0, 0, 0, 0, 0 },
|
/* v */ { 1, 0, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 12, 15, 0, 0, 0, 0, 18, 0, 19, 0, 0, 0, 0, 0 },
|
||||||
/* w */ { 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 8, 0, 9, 10, 0, 0, 0, 12, 13, 0, 0, 0, 0 },
|
/* w */ { 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 8, 0, 9, 10, 0, 0, 0, 12, 13, 0, 0, 0, 0 },
|
||||||
@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] =
|
|||||||
/* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
/* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int command_count = 592;
|
static const int command_count = 594;
|
||||||
|
@ -126,7 +126,7 @@ EXCMD(CMD_abclear, "abclear", ex_abclear,
|
|||||||
EXCMD(CMD_aboveleft, "aboveleft", ex_wrongmodifier,
|
EXCMD(CMD_aboveleft, "aboveleft", ex_wrongmodifier,
|
||||||
EX_NEEDARG|EX_EXTRA|EX_NOTRLCOM,
|
EX_NEEDARG|EX_EXTRA|EX_NOTRLCOM,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_abstract, "abstract", ex_ni,
|
EXCMD(CMD_abstract, "abstract", ex_class,
|
||||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_all, "all", ex_all,
|
EXCMD(CMD_all, "all", ex_all,
|
||||||
@ -354,7 +354,7 @@ EXCMD(CMD_clist, "clist", qf_list,
|
|||||||
EXCMD(CMD_clast, "clast", ex_cc,
|
EXCMD(CMD_clast, "clast", ex_cc,
|
||||||
EX_RANGE|EX_COUNT|EX_TRLBAR|EX_BANG,
|
EX_RANGE|EX_COUNT|EX_TRLBAR|EX_BANG,
|
||||||
ADDR_UNSIGNED),
|
ADDR_UNSIGNED),
|
||||||
EXCMD(CMD_class, "class", ex_ni,
|
EXCMD(CMD_class, "class", ex_class,
|
||||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
|
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_close, "close", ex_close,
|
EXCMD(CMD_close, "close", ex_close,
|
||||||
@ -567,16 +567,16 @@ EXCMD(CMD_emenu, "emenu", ex_emenu,
|
|||||||
EXCMD(CMD_endif, "endif", ex_endif,
|
EXCMD(CMD_endif, "endif", ex_endif,
|
||||||
EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_endinterface, "endinterface", ex_ni,
|
EXCMD(CMD_endinterface, "endinterface", ex_wrongmodifier,
|
||||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_endclass, "endclass", ex_ni,
|
EXCMD(CMD_endclass, "endclass", ex_wrongmodifier,
|
||||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_enddef, "enddef", ex_endfunction,
|
EXCMD(CMD_enddef, "enddef", ex_endfunction,
|
||||||
EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_endenum, "endenum", ex_ni,
|
EXCMD(CMD_endenum, "endenum", ex_wrongmodifier,
|
||||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_endfunction, "endfunction", ex_endfunction,
|
EXCMD(CMD_endfunction, "endfunction", ex_endfunction,
|
||||||
@ -594,7 +594,7 @@ EXCMD(CMD_endwhile, "endwhile", ex_endwhile,
|
|||||||
EXCMD(CMD_enew, "enew", ex_edit,
|
EXCMD(CMD_enew, "enew", ex_edit,
|
||||||
EX_BANG|EX_TRLBAR,
|
EX_BANG|EX_TRLBAR,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_enum, "enum", ex_ni,
|
EXCMD(CMD_enum, "enum", ex_enum,
|
||||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
|
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_eval, "eval", ex_eval,
|
EXCMD(CMD_eval, "eval", ex_eval,
|
||||||
@ -756,7 +756,7 @@ EXCMD(CMD_inoremenu, "inoremenu", ex_menu,
|
|||||||
EXCMD(CMD_intro, "intro", ex_intro,
|
EXCMD(CMD_intro, "intro", ex_intro,
|
||||||
EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_interface, "interface", ex_ni,
|
EXCMD(CMD_interface, "interface", ex_interface,
|
||||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_isearch, "isearch", ex_findpat,
|
EXCMD(CMD_isearch, "isearch", ex_findpat,
|
||||||
@ -1215,6 +1215,9 @@ EXCMD(CMD_ptselect, "ptselect", ex_ptag,
|
|||||||
EXCMD(CMD_put, "put", ex_put,
|
EXCMD(CMD_put, "put", ex_put,
|
||||||
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_REGSTR|EX_TRLBAR|EX_ZEROR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
|
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_REGSTR|EX_TRLBAR|EX_ZEROR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
|
||||||
ADDR_LINES),
|
ADDR_LINES),
|
||||||
|
EXCMD(CMD_public, "public", ex_wrongmodifier,
|
||||||
|
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||||
|
ADDR_NONE),
|
||||||
EXCMD(CMD_pwd, "pwd", ex_pwd,
|
EXCMD(CMD_pwd, "pwd", ex_pwd,
|
||||||
EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
@ -1488,7 +1491,7 @@ EXCMD(CMD_startgreplace, "startgreplace", ex_startinsert,
|
|||||||
EXCMD(CMD_startreplace, "startreplace", ex_startinsert,
|
EXCMD(CMD_startreplace, "startreplace", ex_startinsert,
|
||||||
EX_BANG|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
EX_BANG|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_static, "static", ex_ni,
|
EXCMD(CMD_static, "static", ex_wrongmodifier,
|
||||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_stopinsert, "stopinsert", ex_stopinsert,
|
EXCMD(CMD_stopinsert, "stopinsert", ex_stopinsert,
|
||||||
@ -1614,6 +1617,9 @@ EXCMD(CMD_tfirst, "tfirst", ex_tag,
|
|||||||
EXCMD(CMD_throw, "throw", ex_throw,
|
EXCMD(CMD_throw, "throw", ex_throw,
|
||||||
EX_EXTRA|EX_NEEDARG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
EX_EXTRA|EX_NEEDARG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
|
EXCMD(CMD_this, "this", ex_wrongmodifier,
|
||||||
|
EX_EXTRA|EX_NEEDARG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
||||||
|
ADDR_NONE),
|
||||||
EXCMD(CMD_tjump, "tjump", ex_tag,
|
EXCMD(CMD_tjump, "tjump", ex_tag,
|
||||||
EX_BANG|EX_TRLBAR|EX_WORD1,
|
EX_BANG|EX_TRLBAR|EX_WORD1,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
@ -1665,7 +1671,7 @@ EXCMD(CMD_tunmenu, "tunmenu", ex_menu,
|
|||||||
EXCMD(CMD_tunmap, "tunmap", ex_unmap,
|
EXCMD(CMD_tunmap, "tunmap", ex_unmap,
|
||||||
EX_EXTRA|EX_TRLBAR|EX_NOTRLCOM|EX_CTRLV|EX_CMDWIN|EX_LOCK_OK,
|
EX_EXTRA|EX_TRLBAR|EX_NOTRLCOM|EX_CTRLV|EX_CMDWIN|EX_LOCK_OK,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_type, "type", ex_ni,
|
EXCMD(CMD_type, "type", ex_type,
|
||||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
|
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_undo, "undo", ex_undo,
|
EXCMD(CMD_undo, "undo", ex_undo,
|
||||||
|
@ -267,6 +267,7 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name);
|
|||||||
# define ex_breaklist ex_ni
|
# define ex_breaklist ex_ni
|
||||||
# define ex_call ex_ni
|
# define ex_call ex_ni
|
||||||
# define ex_catch ex_ni
|
# define ex_catch ex_ni
|
||||||
|
# define ex_class ex_ni
|
||||||
# define ex_compiler ex_ni
|
# define ex_compiler ex_ni
|
||||||
# define ex_continue ex_ni
|
# define ex_continue ex_ni
|
||||||
# define ex_debug ex_ni
|
# define ex_debug ex_ni
|
||||||
@ -282,10 +283,12 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name);
|
|||||||
# define ex_endif ex_ni
|
# define ex_endif ex_ni
|
||||||
# define ex_endtry ex_ni
|
# define ex_endtry ex_ni
|
||||||
# define ex_endwhile ex_ni
|
# define ex_endwhile ex_ni
|
||||||
|
# define ex_enum ex_ni
|
||||||
# define ex_eval ex_ni
|
# define ex_eval ex_ni
|
||||||
# define ex_execute ex_ni
|
# define ex_execute ex_ni
|
||||||
# define ex_incdec ex_ni
|
|
||||||
# define ex_finally ex_ni
|
# define ex_finally ex_ni
|
||||||
|
# define ex_incdec ex_ni
|
||||||
|
# define ex_interface ex_ni
|
||||||
# define ex_finish ex_ni
|
# define ex_finish ex_ni
|
||||||
# define ex_function ex_ni
|
# define ex_function ex_ni
|
||||||
# define ex_if ex_ni
|
# define ex_if ex_ni
|
||||||
@ -300,6 +303,7 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name);
|
|||||||
# define ex_scriptnames ex_ni
|
# define ex_scriptnames ex_ni
|
||||||
# define ex_throw ex_ni
|
# define ex_throw ex_ni
|
||||||
# define ex_try ex_ni
|
# define ex_try ex_ni
|
||||||
|
# define ex_type ex_ni
|
||||||
# define ex_unlet ex_ni
|
# define ex_unlet ex_ni
|
||||||
# define ex_while ex_ni
|
# define ex_while ex_ni
|
||||||
# define ex_import ex_ni
|
# define ex_import ex_ni
|
||||||
@ -6693,12 +6697,13 @@ ex_recover(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Command modifier used in a wrong way.
|
* Command modifier used in a wrong way. Also for other commands that can't
|
||||||
|
* appear at the toplevel.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ex_wrongmodifier(exarg_T *eap)
|
ex_wrongmodifier(exarg_T *eap)
|
||||||
{
|
{
|
||||||
eap->errmsg = _(e_invalid_command);
|
eap->errmsg = ex_errmsg(e_invalid_command_str, eap->cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -215,6 +215,7 @@ void mbyte_im_set_active(int active_arg);
|
|||||||
# ifdef FEAT_EVAL
|
# ifdef FEAT_EVAL
|
||||||
// include vim9.h here, the types defined there are used by function arguments.
|
// include vim9.h here, the types defined there are used by function arguments.
|
||||||
# include "vim9.h"
|
# include "vim9.h"
|
||||||
|
# include "vim9class.pro"
|
||||||
# include "vim9cmds.pro"
|
# include "vim9cmds.pro"
|
||||||
# include "vim9compile.pro"
|
# include "vim9compile.pro"
|
||||||
# include "vim9execute.pro"
|
# include "vim9execute.pro"
|
||||||
|
6
src/proto/vim9class.pro
Normal file
6
src/proto/vim9class.pro
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/* vim9class.c */
|
||||||
|
void ex_class(exarg_T *eap);
|
||||||
|
void ex_interface(exarg_T *eap);
|
||||||
|
void ex_enum(exarg_T *eap);
|
||||||
|
void ex_type(exarg_T *eap);
|
||||||
|
/* vim: set ft=c : */
|
@ -15,6 +15,16 @@ def Test_cmdmods_array()
|
|||||||
lines = getline(top, bot)
|
lines = getline(top, bot)
|
||||||
var mods = lines->map((_, v) => substitute(v, '.*"\(\k*\)".*', '\1', ''))
|
var mods = lines->map((_, v) => substitute(v, '.*"\(\k*\)".*', '\1', ''))
|
||||||
|
|
||||||
|
# Add the other commands that use ex_wrongmodifier.
|
||||||
|
mods->extend([
|
||||||
|
'endclass',
|
||||||
|
'endenum',
|
||||||
|
'endinterface',
|
||||||
|
'public',
|
||||||
|
'static',
|
||||||
|
'this',
|
||||||
|
])
|
||||||
|
|
||||||
# Check the lists are equal. Convert them to a dict to get a clearer error
|
# Check the lists are equal. Convert them to a dict to get a clearer error
|
||||||
# message.
|
# message.
|
||||||
var cmds_dict = {}
|
var cmds_dict = {}
|
||||||
|
@ -695,6 +695,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1001,
|
||||||
/**/
|
/**/
|
||||||
1000,
|
1000,
|
||||||
/**/
|
/**/
|
||||||
|
110
src/vim9class.c
Normal file
110
src/vim9class.c
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/* vi:set ts=8 sts=4 sw=4 noet:
|
||||||
|
*
|
||||||
|
* VIM - Vi IMproved by Bram Moolenaar
|
||||||
|
*
|
||||||
|
* Do ":help uganda" in Vim to read copying and usage conditions.
|
||||||
|
* Do ":help credits" in Vim to see a list of people who contributed.
|
||||||
|
* See README.txt for an overview of the Vim source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vim9class.c: Vim9 script class support
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define USING_FLOAT_STUFF
|
||||||
|
#include "vim.h"
|
||||||
|
|
||||||
|
#if defined(FEAT_EVAL) || defined(PROTO)
|
||||||
|
|
||||||
|
// When not generating protos this is included in proto.h
|
||||||
|
#ifdef PROTO
|
||||||
|
# include "vim9.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle ":class" and ":abstract class" up to ":endclass".
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ex_class(exarg_T *eap)
|
||||||
|
{
|
||||||
|
int is_abstract = eap->cmdidx == CMD_abstract;
|
||||||
|
|
||||||
|
char_u *arg = eap->arg;
|
||||||
|
if (is_abstract)
|
||||||
|
{
|
||||||
|
if (STRNCMP(arg, "class", 5) != 0 || !VIM_ISWHITE(arg[5]))
|
||||||
|
{
|
||||||
|
semsg(_(e_invalid_argument_str), arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
arg = skipwhite(arg + 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ASCII_ISUPPER(*arg))
|
||||||
|
{
|
||||||
|
semsg(_(e_class_name_must_start_with_uppercase_letter_str), arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// generics: <Tkey, Tentry>
|
||||||
|
// extends SomeClass
|
||||||
|
// implements SomeInterface
|
||||||
|
// specifies SomeInterface
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: handle until "endclass" is found:
|
||||||
|
// object and class members (public, read access, private):
|
||||||
|
// public this.varname
|
||||||
|
// public static varname
|
||||||
|
// this.varname
|
||||||
|
// static varname
|
||||||
|
// this._varname
|
||||||
|
// static _varname
|
||||||
|
//
|
||||||
|
// constructors:
|
||||||
|
// def new()
|
||||||
|
// enddef
|
||||||
|
// def newOther()
|
||||||
|
// enddef
|
||||||
|
//
|
||||||
|
// methods (object, class, generics):
|
||||||
|
// def someMethod()
|
||||||
|
// enddef
|
||||||
|
// static def someMethod()
|
||||||
|
// enddef
|
||||||
|
// def <Tval> someMethod()
|
||||||
|
// enddef
|
||||||
|
// static def <Tval> someMethod()
|
||||||
|
// enddef
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle ":interface" up to ":endinterface".
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ex_interface(exarg_T *eap UNUSED)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle ":enum" up to ":endenum".
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ex_enum(exarg_T *eap UNUSED)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle ":type".
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ex_type(exarg_T *eap UNUSED)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // FEAT_EVAL
|
Loading…
x
Reference in New Issue
Block a user