Making Emacs a better editor for HaXe

568 views
Skip to first unread message

Left Right

unread,
Jun 14, 2012, 5:12:55 AM6/14/12
to haxe...@googlegroups.com
Hello,

I've couple of thoughts and questions on how it might be possible to enhance the editing of HaXe code in Emacs.

First, a little achievement: flymake (syntax checking) appeared to be quite easy, although I've to find a way to make it check individual file that might be valid on their own, but aren't part of the project (yet). I.e. in a situation when you have a class that isn't yet referenced anywhere in the project, but it can't compile on its own (on targets like Flash there's a requirement of extending DisplayObject for example).

The question thus: is there a way to run HaXe compiler in a syntax-check mode so that it doesn't produce binaries, also no need to do the post-parsing operations (like inlining or macros expansion etc)?

Second, a somewhat mixed achievement: I tried generating TAGS file pretending *.hx files are written in C. It was quite a surprise the TAGS file was usable to an extend. It, however, parsed import statements as if those were declarations and completely neglected function declarations. So I could go to the source of a property or the class, but not a function using M-.

The question: is it possible to request this information from compiler in some way? To expand on this. TAGS file contains information about the file that declares some interesting entities of the program, usually classes, functions, structs, typedefs, class fields etc. It is a relatively simple and documented format to write, so, even if the compiler itself isn't able to produce precisely the format required, it shouldn't be in general very difficult to create such file given the information at all present.

Autocompletion: using autocomplete extension I could get some autocompletion for the keywords and lexical completion within the open files, which is a start, but its unreliable. I can recall that the compiler used to provide autocompletion service for FD, is that model still valid, and if so, how can I request the compiler for autocompletion options given the context etc? To be honest, I've only got familiar with autocomplete library couple of days ago, so I don't know how difficult it would be to connect them two, but I would try.

Lastly. This seems to be the hardest. Can you comment on the idea of having REPL using, for example, neko server? I must confess, I know very little about neko, so I would need your advise to tell me if what I'm asking is at all doable. If you don't know what REPL is - it is an interactive shell, where you can send your code to, your code gets evaluated and you can then use it in the shell in an interactive way. I believe that the idea comes from Lisp (although maybe Algol and older languages had something like this too - I'm not old enough to know, so please excuse me!), but many other languages have it too, for example Python, Erlang, Haskell and many more.

What is required to have REPL: an ability to load a definition of a program entity (such as class, function etc) into an environment running the program dynamically. Dynamically in this context means that the definition can be overwritten successively many times. This is something you cannot do in Flash in many instances, you wouldn't be able to do this with ClassLoader in Java too, for example. And, of course, an ability to send code that uses that definition into REPL, have it evaluated and have the result printed.

There are obvious problems with it: a lot of languages HaXe complies to have dependencies on GUI or other environments that run them, however, there's an approach you can take with, for example, Node.js server (it is used with jslint for JavaScript REPL) to test what they call "algorithmic" code. I.e. the code that doesn't depend on browser's DOM. It actually appears quite practical.

So, there are, potentially, several possible options, but all of them have pitfalls:
- compile HaXe to JavaScript and use Node.js for the REPL (JavaScript target may not allow many things generally possible on other targets due to lack of proper bytes / arrays of bytes etc). It would require loading the entire JS code generated that backs up HaXe functionality in JavaScript whenever you send a new definition to REPL (might be quite expensive). Sending plain HaXe code to the shell isn't possible (needs compiling it to JS).
- compile HaXe to PHP. PHP too has some interactive shell that can be used for the same purpose, but most of the same problems JavaScript has are present too.

This is why, basically, I'm asking about what is possible to do with neko.

Normally, REPL would also be used for debugging, but this would be problematic given the polymorphic nature of the language. However, I've some ideas on how it might be possible to connect fdb to Emacs to have some sort of interactive debugger for SWFs, although this looks like loads of work... :(

Thanks, would be happy to hear any feedback.

Left Right

unread,
Jun 14, 2012, 7:28:11 AM6/14/12
to haxe...@googlegroups.com
Answering some of my own questions, I've found this: http://haxe.org/manual/completion and I'm going to try to see what I can do with it. I also saw neko --interpret option, which got me curious about the possibility of interactive code evaluation.

ritchie turner

unread,
Jun 14, 2012, 7:42:07 AM6/14/12
to haxe...@googlegroups.com

https://github.com/cloudshift/hx-emacs
> --
> To post to this group haxe...@googlegroups.com
> http://groups.google.com/group/haxelang?hl=en


--
Simplicity is the ultimate sophistication. ~ Leonardo da Vinci

Left Right

unread,
Jun 14, 2012, 8:29:09 AM6/14/12
to haxe...@googlegroups.com
Absolutely cool, thanks!

However, I've some thoughts about modifying it, if you don't mind.
1. Rather than doing plain  open-network-stream, I'd go for a dedicated buffer (wouldn't it be easier to snoop on what's been sent back and forth using it?).
2. I'd rather use autocomplete extension http://cx4a.org/software/auto-complete/ instead of doing the UI stuff on my own, besides, I think it looks pretty :) and it is in fact quite intelligent when filtering suggestions.
3. Use http://www.emacswiki.org/emacs/XmlParserExamples Xml Parser to parse what HaXe compiler sends (even though it's not complex enough yet - who knows, it might get more complex some time, so if it's Xml, this looks like the right tool to do it).

So, with your permission, I'd like to modify it a bit, is that fine? I'm surely share it once it is workable.

PS, I didn't use EDE or any other kind of project, but below is my attempt at flymake integration, if you don't have it yet, probably one thing you'd like to change is the way *.hxml file is located

(defvar *haxe-compiler* "haxe"
  "The path to HaXe compiler")

(defvar *build-hxml* "build.hxml"
  "The name of the nxml file to build the project")

(defvar *project-root* "./src/"
  "The name of the project source directory.
Upon load the value will be replaced with the `src' 
directory found on the path to the loaded file.
This is the best I could do for now")

(defun create-haxe-tags (dir-name)
  "Create HaXe tags file."
  ;; TODO: we can use haxe -xml here to generate the XML
  ;; and parse it into TAGS file instead.
  (interactive "DDirectory: ")
  (eshell-command 
   (format "find %s -type f -name \"*.hx\" | etags -L -" dir-name)))

(defun haxe-flymake-install ()
  "install flymake stuff for HaXe files."
  (add-to-list
   'compilation-error-regexp-alist
   '("^\\([^: ]+\\):\\([0-9]+\\): characters \\([0-9]+\\)-[0-9]+ : "
     1 2 3))
  (message "haxe flymake installed")
  (let* ((key "\\.hx\\'")
         (haxeentry (assoc key flymake-allowed-file-name-masks)))
    (if haxeentry
        (setcdr haxeentry '(haxe-flymake-init haxe-flymake-cleanup))
      (add-to-list
       'flymake-allowed-file-name-masks
       (list key 'haxe-flymake-init 'haxe-flymake-cleanup)))))

(defun haxe-flymake-init ()
  "initialize flymake for HaXe."
  (let ((create-temp-f ' haxe-flymake-create-temp-intemp)
        (use-relative-base-dir nil)
        (use-relative-source nil)
        (get-cmdline-f 'haxe-flymake-get-cmdline)
        args
        temp-source-file-name)
    (message "flymake haxe init")
    (setq temp-source-file-name
 (flymake-init-create-temp-buffer-copy create-temp-f)
          args (flymake-get-syntax-check-program-args
                temp-source-file-name *project-root*
                use-relative-base-dir use-relative-source
                get-cmdline-f))
    args))

(defun haxe-flymake-get-cmdline (source base-dir)
  "Gets the cmd line for running a flymake session in a HaXe buffer.
This gets called by flymake itself. The output is a list of two elements:
the command to run, and a list of arguments.  The resulting command is like:

  $ haxe ${project-root}/build.hxml

"
  (message "base-dir %s" (file-name-as-directory base-dir))
  (list *haxe-compiler*
        (list
(concat (file-name-as-directory base-dir)
*build-hxml*))))

(defun haxe-flymake-cleanup ()
  (flymake-simple-cleanup))

(defun haxe-flymake-create-temp-intemp (file-name prefix)
  "Return file name in temporary directory for checking FILE-NAME.
This is a replacement for `flymake-create-temp-inplace'. The
difference is that it gives a file name in
`temporary-file-directory' instead of the same directory as
FILE-NAME.

For the use of PREFIX see that function.

This won't always work; it will fail if the source module
refers to relative paths.
"
  (message "creating temp buffer")
  (unless (stringp file-name)
    (error "Invalid file-name"))
  (or prefix
      (setq prefix "flymake"))
  (let* ((name (concat
                prefix "-"
                (file-name-nondirectory
                 (file-name-sans-extension file-name))
                "-"))
         (ext  (concat "." (file-name-extension file-name)))
         (temp-name (make-temp-file name nil ext)))
    (flymake-log 3 "create-temp-intemp: file=%s temp=%s" file-name temp-name)
    temp-name))

(defun haxe-idenatify-project-root ()
  "Lame attempt at finding the root directory of our project.
The assumtion is that most people would call it `src', so we 
climb up the directory tree to see if there's a directory with this
name on the path and assume the last such instance to be our project
directory, for example /home/user/projects/foo/src/org/user/utils/Bar.hx
wil result in /home/user/projects/foo/src/ being selected as the root
directory"
  (let* ((current (buffer-file-name))
(pos (string-match "/src/" current)))
    (when pos
      (setq *project-root* (substring current 0 pos)))))

I've also added this to haxe-mode as hooks:

  (haxe-flymake-install)
  (haxe-idenatify-project-root)
  (flymake-mode)
  (auto-complete-mode 1)

in the .emacs

(add-to-list 'ac-modes 'haxe-mode) 

You would also need this file called "haxe-mode" in the "dict" directory inside autocomplete directory before you compile:

class
interface
enum
typedef
function
var
import
package
private
public
static
override
do
else
try
for
if
switch
while
catch
false
true
null
this
super
in
Array
ArrayAccess
Bool
Class
Date
DateTools
Dynamic
EReg
Enum
EnumValue
Float
Hash
Int
IntHash
IntIter
Iterable
Iterator
Lambda
List
Math
Null
Reflect
Std
String
StringBuf
StringTools
Sys
Type
UInt
ValueType
Void
Xml
XmlType

This provides some more completion beyond what HaXe compiler would normally give you (after dot or parenthesis).

Sorry for the long post, it's not yet tidy enough so I could host it somewhere for better access.

Best.

Oleg

Thom Chiovoloni

unread,
Jun 14, 2012, 11:20:23 AM6/14/12
to haxe...@googlegroups.com
Better HaXe integration for emacs would be amazing, but I'd be way more interested in a REPL.  The lack of one is one of my largest annoyances about the language, to be honest. 

Left Right

unread,
Jun 17, 2012, 11:58:50 AM6/17/12
to haxe...@googlegroups.com
https://code.google.com/p/haxe-mode/source/browse/haxe-mode.el

This is my mod of the haxe-mode (compilation of two pre-existing ones + some my additions). It's ~50% workable, but it's extremely fragile and has tons of bugs (yet!). I'm going to continue to work on it, but would appreciate early feedback (and fixes!). I'm not a guru of eLisp so, there's a good chance things could be done differently and better. Besides, if you have any ideas or wishes for something that you think will be comparatively easy to add - I'll probably try to add it, at least :)

Several things that might require attention:
- TAGS files (this is how you do code navigation and, in some distant future - refactoring), very little is done yet, though this should be relatively easy.
- Autocompletion (sort of works, but has lots of glitches, some known ones: if you select an item from the list w/o typing anything, it will delete the preceding dot, no idea why it does it. The candidate selection has to be more clever (I have something lined up, but it's not ready yet). I've vague understanding of what happens once many buffers are open. What I tried to do is to reuse the connection to the compiler in every new buffer, but I'm not sure that's what I'm doing, so if you see how it may be improved - you are welcome to. Help display can be improved with additional faces and all the fancy-pretty stuff...
- Flymake when combined with autocompletion it messes up things, so I added some ugly patch to prevent flymake from making syntax checks on any even spare saving buffer. If you have an idea on how to improve this, you are welcome to.

I would still like very much to learn about a possibility to run neko server as interpreter. Even a limited PoC would do. Otherwise I've a plan to try to make friends with Node.js and see if it would be possible to use it to have some kind of REPL for HaXe, but nothing has been done in this direction.

Best.

Oleg

Left Right

unread,
Jun 18, 2012, 5:07:23 AM6/18/12
to haxe...@googlegroups.com
http://s13.postimage.org/m81jpvd1z/haxe_electric_help.png

A tiny update and a question. :)

There's yet another thing that is typical to do in Emacs: (separate) help pages for interesting artifacts of the language. I've made this as an example (this is usually known as "electric help", for example, to get help on function you'd do C-h f, help on variable C-h v and so on.
I've an idea on how to show some relevant help on literals (such as strings and numbers) as in example above, but more useful help would be in displaying some text describing some interesting artifacts. I could imagine how to find programmer-created artifacts (such as documentation for classes, functions and variables) from $ haxe -xml, but where would I get some description for HaXe language itself, i.e. things like operators, keywords, special constructions, preprocessor instructions?

Best.

Oleg

ritchie turner

unread,
Jun 18, 2012, 8:24:02 AM6/18/12
to haxe...@googlegroups.com

I'm no elisp expert, and hacked together what I could, it's certainly less than optimal.

Pls fork it and I'll use your version :)

Ritchie

Left Right

unread,
Jun 18, 2012, 1:38:10 PM6/18/12
to haxe...@googlegroups.com
I will, I will! 
Some time more towards the end of this week (I hope...) I'll get it to the point where it doesn't break very often :)

Here are couple more things, I'm trying to figure out yet:

- I'm using ECB (Emacs Code Browser) - it provides outlines (the list of functions / classes / etc) for many other languages, which is actually quite comfortable. I still need to understand how much work it is going to take to interface with it. Because if I got this (and I hope it shouldn't be much of a problem), then we could also have outlines (almost like grown-up IDEs!) ECB also has good interface to building systems aka make/ant/maven/scons etc. which I never used :S

- Debugging. This sounds tough, but I can remember being able to debug HaXe SWF in fdb, similarly it may be possible to debug HaXe JavaScript in Node.js. I've no idea about how you debug neko, and it seems like debugging C++ code generated from HaXe in gdb is just the same as debugging C++ code in gdb (nightmarish, judging from the expression on the faces of few people who heard me mention it).

- Projects. I don't usually use EDE, but maybe I should, and I'll see if it would be possible to come up with some sort of a project template. (Or maybe use hxml as an improvised "project" - is it possible, or people usually need more settings than it is possible to specify there? Is it possible to put comments into hxml?)

- Linking resources. This is a gray area for me, I know very little of what HaXe can do in this regard (outside Flash, but even there - not so much). I also don't know what is the idiomatic way for Emacs to deal with it.

- Finally, there are couple of problematic places in the syntax parser: it assumes all types start with upper-case letter... breaking lines works ugly (they break to the beginning of the previous line and I've no idea where to set this / this well may be an artifact of some other setting being wrong in order to fix something else, and I'm afraid to touch it, because it's coming from c-mode and it's just too huge for my feeble brain). There's basically no code model behind the coloring because it is for the most part a some kind of a lucky guess, so if I wanted to, for example, find all functions in the buffer, I'd need to write the lexer from scratch (or who knows how that c-mode works?!)

- Building projects. Is it safe to assume most people just use nxml files to build them, or should it maybe prefer make files as the default configuration? I saw people using Ant (even Maven!) to build HaXe projects.

- Haxelib. It actually may be possible to have an interface to haxelib, at least to query for installed modules / ask it to install if something is missing (separate task).

- I'm hoping to achieve too much :)
Reply all
Reply to author
Forward
0 new messages