GNU bug report logs -
#61368
[PATCH] Extend go-ts-mode with support for pre-filling return statements
Previous Next
To reply to this bug, email your comments to 61368 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Wed, 08 Feb 2023 15:29:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Evgeni Kolev <evgenysw <at> gmail.com>
:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org
.
(Wed, 08 Feb 2023 15:29:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
[CC Randy, author of go-ts-mode, Theo, who asked to keep the patches coming :)]
This is a patch which adds support to go-ts-mode to insert
context-aware return statements for the current function. The return
statements are pre-filled with the Go zero values of the output
parameters.
For example, all these return statements are inserted by M-x
go-ts-mode-insert-return:
```
func f() (x, y, z int) {
return 0, 0, 0
}
func exotic() (bool, int, myStruct, *int, chan bool, error) {
return false, 0, myStruct{}, nil, nil, err
}
func closure(numbers []int) {
sort.Slice(numbers, func(i, j int) bool {
return false
})
}
```
The command go-ts-mode-insert-return is experimentally bound to a key
C-c C-r ("r" as return statement). It's a user error to run C-c C-r
outside of a function body.
Customization: when the output params contain "error" the pre-filled
text is "err". A customization variable is added to allow the user to
pick a different value, for example they might pick `fmt.Errorf("...:
%w", err)` which will result in error wrapping:
```
func f() (int, error) {
return 0, fmt.Errorf("...: %w", err)
}
```
Personally, I'll use yasnippet instead of C-c C-r. Something like this:
```
# -*- mode: snippet -*-
# name: ret
# key: ret
# type: command
# --
(let ((go-ts-mode-error-zero-value "${1:fmt.Errorf(\"${2:format}:
%w\", err)}"))
(yas-expand-snippet (go-ts-mode-return)))
```
I'm open to suggestions about how to best expose this functionality to
the user. I think a snippet makes the most sense, but there's no
standard way for major modes to expose snippets as far as I'm aware.
It's possible to tweak C-c C-r to call (yas-expand-snippet) if
available, otherwise call (insert). In general, I don't feel strong
about the C-c C-r key binding, but I didn't have a better idea.
Known bug: this example does not work, fails with error "Unknown Go
type "[int]int"":
```
func notOk() (int, map[int]int) {
}
```
The root cause is an issue with the tree-sitter-go parser. The bug has
been reported here
https://github.com/tree-sitter/tree-sitter-go/issues/107
Known limitation: unfamiliar types are assumed to be structs. This
assumption does not work for aliased types. For example:
```
type MyInt = int
func alias() MyInt {
return MyInt{}
}
```
Above the correct return statement is "return MyInt(0)". My assumption
is that type aliases of primitive types are rare in Go codebases. In
these rare cases, the user is expected to replace "MyInt{}" with
"MyInt(0)", or not use C-c C-r at all.
Inspired by: this emacs conf talk "08:21 Intelligent templates"
https://emacsconf.org/2022/talks/treesitter/
Feedback is more than welcome! In particular:
- how to best expose the functionality - key binding, snippet (how
exactly?), something else?
Evgeni
[0001-Extend-go-ts-mode-with-support-for-pre-filling-retur.patch (application/x-patch, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Wed, 08 Feb 2023 16:31:01 GMT)
Full text and
rfc822 format available.
Message #8 received at 61368 <at> debbugs.gnu.org (full text, mbox):
> Cc: Randy Taylor <dev <at> rjt.dev>, Theodor Thornhill <theo <at> thornhill.no>
> From: Evgeni Kolev <evgenysw <at> gmail.com>
> Date: Wed, 8 Feb 2023 17:27:58 +0200
>
> This is a patch which adds support to go-ts-mode to insert
> context-aware return statements for the current function. The return
> statements are pre-filled with the Go zero values of the output
> parameters.
>
> For example, all these return statements are inserted by M-x
> go-ts-mode-insert-return:
>
> ```
> func f() (x, y, z int) {
> return 0, 0, 0
> }
>
> func exotic() (bool, int, myStruct, *int, chan bool, error) {
> return false, 0, myStruct{}, nil, nil, err
> }
>
> func closure(numbers []int) {
> sort.Slice(numbers, func(i, j int) bool {
> return false
> })
> }
> ```
>
> The command go-ts-mode-insert-return is experimentally bound to a key
> C-c C-r ("r" as return statement). It's a user error to run C-c C-r
> outside of a function body.
Instead of a command bound to a special key sequences, would it
perhaps make more sense to add some kind of "electric" behavior to
"normal" keys? Like perhaps typing RET after inserting "return" would
add the "context-aware return statement"? Then the user could turn on
the electric behavior with some minor mode, and get this behavior,
while avoiding the need to dedicate a key sequence.
WDYT?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Wed, 08 Feb 2023 19:21:02 GMT)
Full text and
rfc822 format available.
Message #11 received at submit <at> debbugs.gnu.org (full text, mbox):
Evgeni Kolev <evgenysw <at> gmail.com> writes:
> [CC Randy, author of go-ts-mode, Theo, who asked to keep the patches coming :)]
>
:-)
> This is a patch which adds support to go-ts-mode to insert
> context-aware return statements for the current function. The return
> statements are pre-filled with the Go zero values of the output
> parameters.
>
> For example, all these return statements are inserted by M-x
> go-ts-mode-insert-return:
>
> ```
> func f() (x, y, z int) {
> return 0, 0, 0
> }
>
> func exotic() (bool, int, myStruct, *int, chan bool, error) {
> return false, 0, myStruct{}, nil, nil, err
> }
>
> func closure(numbers []int) {
> sort.Slice(numbers, func(i, j int) bool {
> return false
> })
> }
> ```
Cool!
>
> The command go-ts-mode-insert-return is experimentally bound to a key
> C-c C-r ("r" as return statement). It's a user error to run C-c C-r
> outside of a function body.
>
> Customization: when the output params contain "error" the pre-filled
> text is "err". A customization variable is added to allow the user to
> pick a different value, for example they might pick `fmt.Errorf("...:
> %w", err)` which will result in error wrapping:
> ```
> func f() (int, error) {
> return 0, fmt.Errorf("...: %w", err)
> }
> ```
>
> Personally, I'll use yasnippet instead of C-c C-r. Something like this:
> ```
> # -*- mode: snippet -*-
> # name: ret
> # key: ret
> # type: command
> # --
>
> (let ((go-ts-mode-error-zero-value "${1:fmt.Errorf(\"${2:format}:
> %w\", err)}"))
> (yas-expand-snippet (go-ts-mode-return)))
> ```
>
> I'm open to suggestions about how to best expose this functionality to
> the user. I think a snippet makes the most sense, but there's no
> standard way for major modes to expose snippets as far as I'm aware.
> It's possible to tweak C-c C-r to call (yas-expand-snippet) if
> available, otherwise call (insert). In general, I don't feel strong
> about the C-c C-r key binding, but I didn't have a better idea.
>
How about using tempo or skeleton as fallbacks when yasnippet isn't
installed?
> Known bug: this example does not work, fails with error "Unknown Go
> type "[int]int"":
> ```
> func notOk() (int, map[int]int) {
> }
> ```
> The root cause is an issue with the tree-sitter-go parser. The bug has
> been reported here
> https://github.com/tree-sitter/tree-sitter-go/issues/107
>
> Known limitation: unfamiliar types are assumed to be structs. This
> assumption does not work for aliased types. For example:
> ```
> type MyInt = int
>
> func alias() MyInt {
> return MyInt{}
> }
> ```
> Above the correct return statement is "return MyInt(0)". My assumption
> is that type aliases of primitive types are rare in Go codebases. In
> these rare cases, the user is expected to replace "MyInt{}" with
> "MyInt(0)", or not use C-c C-r at all.
>
> Inspired by: this emacs conf talk "08:21 Intelligent templates"
> https://emacsconf.org/2022/talks/treesitter/
>
> Feedback is more than welcome! In particular:
> - how to best expose the functionality - key binding, snippet (how
> exactly?), something else?
>
Personally I think this should be a contrib to gopls as a code action so
that others can benefit from it. Is upstreaming it to gopls too hard?
Theo
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Thu, 09 Feb 2023 11:48:01 GMT)
Full text and
rfc822 format available.
Message #14 received at 61368 <at> debbugs.gnu.org (full text, mbox):
On Wed, Feb 8, 2023 at 9:20 PM Theodor Thornhill <theo <at> thornhill.no> wrote:
>
> Evgeni Kolev <evgenysw <at> gmail.com> writes:
>
> >
> > I'm open to suggestions about how to best expose this functionality to
> > the user. I think a snippet makes the most sense, but there's no
> > standard way for major modes to expose snippets as far as I'm aware.
> > It's possible to tweak C-c C-r to call (yas-expand-snippet) if
> > available, otherwise call (insert). In general, I don't feel strong
> > about the C-c C-r key binding, but I didn't have a better idea.
> >
>
> How about using tempo or skeleton as fallbacks when yasnippet isn't
> installed?
I've never used either of these packages. Is there a consensus which
one is preferred for major modes to use?
>
> Personally I think this should be a contrib to gopls as a code action so
> that others can benefit from it. Is upstreaming it to gopls too hard?
>
Great suggestion! I did a quick research and this seems to already be
implemented in gopls here:
https://github.com/golang/tools/blob/master/gopls/internal/lsp/source/completion/statements.go#L179
To use it you have to enable "usePlaceholders", reference:
https://github.com/golang/tools/blob/master/gopls/doc/settings.md
Do you think it makes sense go-ts-mode to also have its own
implementation? I think it does - similar to how both gopls (eglot)
and tree sitter provide Imenu candidates. I personally use tree
sitter's Imenu (setq eglot-stay-out-of '(imenu)) because I find it
advantageous to avoid the RPC call to an external process.
Also having a tree sitter implementation is more flexible. For
example, I'm planning to have multiple yasnippet snippets for
different scenarios (wrap the error, don't wrap, return a new error,
etc.). The gopls implementation is ridgid - it only works if there's
an "err" variable in scope, and the trigger is one of these three "if
e", "if er" and "if err".
On Wed, Feb 8, 2023 at 6:30 PM Eli Zaretskii <eliz <at> gnu.org> wrote:
> > The command go-ts-mode-insert-return is experimentally bound to a key
> > C-c C-r ("r" as return statement). It's a user error to run C-c C-r
> > outside of a function body.
>
> Instead of a command bound to a special key sequences, would it
> perhaps make more sense to add some kind of "electric" behavior to
> "normal" keys? Like perhaps typing RET after inserting "return" would
> add the "context-aware return statement"? Then the user could turn on
> the electric behavior with some minor mode, and get this behavior,
> while avoiding the need to dedicate a key sequence.
>
> WDYT?
Makes sense. I am familiar with electric-pair-mode. I see that it adds
a hook in post-self-insert-hook. Is your suggestion to do something
like this:
- add hook in post-self-insert-hook
- in the hook check if RET is typed after an "return"
- if yes, replace the "return" with the "context-aware return
statement", possibly using (yas-expand-snippet)
I'm wondering what customization options would make sense for users -
changing the electric trigger from "return" RET to "ret" RET for
example.
Is there another major mode which can be used as an example for such
electric behavior?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Thu, 09 Feb 2023 13:41:02 GMT)
Full text and
rfc822 format available.
Message #17 received at 61368 <at> debbugs.gnu.org (full text, mbox):
> From: Evgeni Kolev <evgenysw <at> gmail.com>
> Date: Thu, 9 Feb 2023 13:47:01 +0200
> Cc: 61368 <at> debbugs.gnu.org, dev <at> rjt.dev, theo <at> thornhill.no
>
> > Instead of a command bound to a special key sequences, would it
> > perhaps make more sense to add some kind of "electric" behavior to
> > "normal" keys? Like perhaps typing RET after inserting "return" would
> > add the "context-aware return statement"? Then the user could turn on
> > the electric behavior with some minor mode, and get this behavior,
> > while avoiding the need to dedicate a key sequence.
> >
> > WDYT?
>
> Makes sense. I am familiar with electric-pair-mode. I see that it adds
> a hook in post-self-insert-hook. Is your suggestion to do something
> like this:
> - add hook in post-self-insert-hook
> - in the hook check if RET is typed after an "return"
> - if yes, replace the "return" with the "context-aware return
> statement", possibly using (yas-expand-snippet)
Yes, something like that. See electric.el for more examples.
> I'm wondering what customization options would make sense for users -
> changing the electric trigger from "return" RET to "ret" RET for
> example.
>
> Is there another major mode which can be used as an example for such
> electric behavior?
Electric modes are usually minor modes that let major modes customize
them by setting variables. Again, I think you will find examples in
electric.el.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Sat, 18 Feb 2023 11:47:02 GMT)
Full text and
rfc822 format available.
Message #20 received at 61368 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
+ João, author of yasnippet.
Hi, João, I'd appreciate any suggestions you might have. I'm aiming to
extend go-ts-mode with a snippet-like feature. go-ts-mode would be
able to insert a "smart / context-aware" return statement. My question
is - is there a way for major modes to provide yasnippet snippets? My
understanding is the snippets are either created by each user
individually, or distributed as a collection of snippets (e.g.
yasnippet-snippets). Are there any major modes which provide snippets
(I wasn't able to find any in emacs' repo)?
On Thu, Feb 9, 2023 at 3:40 PM Eli Zaretskii <eliz <at> gnu.org> wrote:
> > Makes sense. I am familiar with electric-pair-mode. I see that it adds
> > a hook in post-self-insert-hook. Is your suggestion to do something
> > like this:
> > - add hook in post-self-insert-hook
> > - in the hook check if RET is typed after an "return"
> > - if yes, replace the "return" with the "context-aware return
> > statement", possibly using (yas-expand-snippet)
>
> Yes, something like that. See electric.el for more examples.
>
> Electric modes are usually minor modes that let major modes customize
> them by setting variables. Again, I think you will find examples in
> electric.el.
The attached patch now adds a (go-ts-electric-return-mode) which, when
enabled, replaces "return RET" with a context-aware return statement.
I used sh-script.el's (sh-electric-here-document-mode) as an example.
I'm concerned this electric mode can turn out to be too
aggressive/surprising for the user - "return RET" is a common text to
be entered, I'm not sure the user would always want it to be replaced.
For example, when debugging I might insert return statements all over
the place.
Put differently, I would be more comfortable if there's a distinct
mechanism to trigger the context-aware return, for example with a
trigger key like when a snippet is inserted.
[0001-Extend-go-ts-mode-with-support-for-pre-filling-retur.patch (application/octet-stream, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Sat, 18 Feb 2023 12:16:02 GMT)
Full text and
rfc822 format available.
Message #23 received at 61368 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On Sat, Feb 18, 2023, 11:46 Evgeni Kolev <evgenysw <at> gmail.com> wrote:
> + João, author of yasnippet.
>
> Hi, João, I'd appreciate any suggestions you might have. I'm aiming to
> extend go-ts-mode with a snippet-like feature. go-ts-mode would be
> able to insert a "smart / context-aware" return statement. My question
> is - is there a way for major modes to provide yasnippet snippets? My
> understanding is the snippets are either created by each user
> individually, or distributed as a collection of snippets (e.g.
> yasnippet-snippets).
Snippets can be distributed as files, but that's not a very good way as I
see it today. One of the reasons might be too leverage the TAB and menu
expansion of the yasnippet system. But probably you don't want this, and
snippets can also be defined programmatically, albeit not with a beautiful
language.
Are there any major modes which provide snippets
> (I wasn't able to find any in emacs' repo)?
>
That's because yasnippet is not part of the Emacs repo proper, i.e. the
"core". So adding snippets to major modes in the core would introduce into
the core a dependency on an non-core ELPA package.
Nevertheless, there are ways to conditionally provide functionality based
on whether the non-core package is detected. A soft dependency. In my
opinion it makes sense for popular non-core packages: company,
markdown-mode, yasnippet, etc. Look at Eglot, for example.
João
João
[Message part 2 (text/html, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Mon, 20 Feb 2023 08:55:02 GMT)
Full text and
rfc822 format available.
Message #26 received at 61368 <at> debbugs.gnu.org (full text, mbox):
Thank you João for the input! I think something like this would make
sense in go-ts-mode.el:
```
(with-eval-after-load 'yasnippet
(yas-define-snippets 'go-ts-mode
'(("return" (yas-expand-snippet
(go-ts-mode-return)))
("iferr" (yas-expand-snippet
(format "if err != nil {\n%s\n}"
(go-ts-mode-return)))))))
```
A custom variable go-ts-mode-want-yasnippet could be added to
optionally prevent adding the snippets.
Eli, would you consider something like the code above acceptable as an
alternative to an electric "return" mode?
Having optional yasnippet integration was also brought up by Theo in
this message[1] and this one [2].
[1]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=60805#11
[2]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=60805#17
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Mon, 20 Feb 2023 12:56:01 GMT)
Full text and
rfc822 format available.
Message #29 received at 61368 <at> debbugs.gnu.org (full text, mbox):
> From: Evgeni Kolev <evgenysw <at> gmail.com>
> Date: Mon, 20 Feb 2023 10:54:06 +0200
> Cc: 61368 <at> debbugs.gnu.org, Randy Taylor <dev <at> rjt.dev>,
> Theodor Thornhill <theo <at> thornhill.no>
>
> Thank you João for the input! I think something like this would make
> sense in go-ts-mode.el:
> ```
> (with-eval-after-load 'yasnippet
> (yas-define-snippets 'go-ts-mode
> '(("return" (yas-expand-snippet
> (go-ts-mode-return)))
> ("iferr" (yas-expand-snippet
> (format "if err != nil {\n%s\n}"
> (go-ts-mode-return)))))))
> ```
>
> A custom variable go-ts-mode-want-yasnippet could be added to
> optionally prevent adding the snippets.
>
> Eli, would you consider something like the code above acceptable as an
> alternative to an electric "return" mode?
>
> Having optional yasnippet integration was also brought up by Theo in
> this message[1] and this one [2].
>
> [1]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=60805#11
> [2]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=60805#17
IMO, if we are going to support yasnippet, we should do it in more
than just one mode. So a short addition to just the go-ts-mode will
not do, and if we want to include stuff like that, it should be part
of a larger patch for Emacs 30. Whether this is a good alternative
for some electricity is also a good topic for discussion: electric is
part of Emacs whereas yasnippet isn't, so there are advantages and
disadvantages to this proposal.
Thanks.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Wed, 22 Feb 2023 14:38:03 GMT)
Full text and
rfc822 format available.
Message #32 received at 61368 <at> debbugs.gnu.org (full text, mbox):
Thank you, makes sense. I'll think about the different options and
come up with a proposal.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Wed, 10 Jan 2024 22:44:01 GMT)
Full text and
rfc822 format available.
Message #35 received at 61368 <at> debbugs.gnu.org (full text, mbox):
Evgeni Kolev <evgenysw <at> gmail.com> writes:
> Thank you, makes sense. I'll think about the different options and
> come up with a proposal.
Did you make any progress here?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Mon, 15 Jan 2024 08:23:02 GMT)
Full text and
rfc822 format available.
Message #38 received at 61368 <at> debbugs.gnu.org (full text, mbox):
On Thu, Jan 11, 2024 at 12:43 AM Stefan Kangas <stefankangas <at> gmail.com> wrote:
>
> Evgeni Kolev <evgenysw <at> gmail.com> writes:
>
> > Thank you, makes sense. I'll think about the different options and
> > come up with a proposal.
>
> Did you make any progress here?
I have since come across tempo.el and reviewed its use in org-tempo.el.
While tempo.el is a valid option, I still think yasnippet is a better approach.
However, yasnippet is still not used throughout emacs' core (other
than "light" uses
in eglot.el and python.el, and some faces in the themes).
Please let me know in case a generic mechanism for adding snippets to major
modes has been added - I might have missed it.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Mon, 15 Jan 2024 08:40:02 GMT)
Full text and
rfc822 format available.
Message #41 received at 61368 <at> debbugs.gnu.org (full text, mbox):
Evgeni Kolev <evgenysw <at> gmail.com> writes:
> On Thu, Jan 11, 2024 at 12:43 AM Stefan Kangas <stefankangas <at> gmail.com> wrote:
>>
>> Evgeni Kolev <evgenysw <at> gmail.com> writes:
>>
>> > Thank you, makes sense. I'll think about the different options and
>> > come up with a proposal.
>>
>> Did you make any progress here?
>
> I have since come across tempo.el and reviewed its use in org-tempo.el.
>
> While tempo.el is a valid option, I still think yasnippet is a better approach.
> However, yasnippet is still not used throughout emacs' core (other
> than "light" uses
> in eglot.el and python.el, and some faces in the themes).
>
> Please let me know in case a generic mechanism for adding snippets to major
> modes has been added - I might have missed it.
Perhaps it's time to revisit the snippet.el that Joao has mentioned?
Theo
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#61368
; Package
emacs
.
(Mon, 15 Jan 2024 11:42:02 GMT)
Full text and
rfc822 format available.
Message #44 received at 61368 <at> debbugs.gnu.org (full text, mbox):
On Mon, Jan 15, 2024 at 8:39 AM Theodor Thornhill <theo <at> thornhill.no> wrote:
>
> Evgeni Kolev <evgenysw <at> gmail.com> writes:
>
> > On Thu, Jan 11, 2024 at 12:43 AM Stefan Kangas <stefankangas <at> gmail.com> wrote:
> >>
> >> Evgeni Kolev <evgenysw <at> gmail.com> writes:
> >>
> >> > Thank you, makes sense. I'll think about the different options and
> >> > come up with a proposal.
> >>
> >> Did you make any progress here?
> >
> > I have since come across tempo.el and reviewed its use in org-tempo.el.
> >
> > While tempo.el is a valid option, I still think yasnippet is a better approach.
> > However, yasnippet is still not used throughout emacs' core (other
> > than "light" uses
> > in eglot.el and python.el, and some faces in the themes).
> >
> > Please let me know in case a generic mechanism for adding snippets to major
> > modes has been added - I might have missed it.
>
> Perhaps it's time to revisit the snippet.el that Joao has mentioned?
I've cleaned it up very minimally and put the most recent version here
https://github.com/joaotavora/snippet
It has unit tests which you can run with
/path/to/emacs -Q --batch -l snippet-tests.el -f ert-run-tests-batch-and-exit
Not many docs docs, some docstrings, many TODOs. Have a look.
This bug report was last modified 1 year and 155 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.