Archive for category Programming

Build R package from GNU Emacs on Windows 10

I use Windows 10 machine, at work, with GNU Emacs installed from choco repository. Script from my article Run shiny R application from Emacs was not working like in my old Windows 7. First thing is that it was not founding my R binary and I’ve got error:

apply: Spawning child process: Invalid argument

First thing was adding path to R binary second issue was path to Root of the package

Here is first function based on the one from previous article:

(defun call-r-command (command-list)
  "run R command in shell buffer window

  if there is displayed buffer that have shell it will use that window"
  (let* ((name "*R*")
         (new-buffer (get-buffer-create name))
         (old-buff (get-buffer name))
         ;; run R command
         (script-proc-buffer
          (apply 'make-comint-in-buffer
                 "script"
                 new-buffer
                 "c:/Program Files/R/R-3.5.2/bin/R.exe"
                 nil
                 command-list))
         ;; if there is *R* buffer try to find its window
         (old-window (if old-buff (get-buffer-window old-buff)))
         ;; use old window or find any that have shell mode
         (window (or old-window
                     (get-window-with-mode '(comint-mode eshell-mode))))
       (script-proc (get-buffer-process script-proc-buffer)))
    ;; reuse window or create new one
    (if window
        (set-window-buffer window new-buffer)
      (switch-to-buffer-other-window new-buffer))))

This function execute R command, so my new shiny function is shorter

(defun shiny ()
  "run shiny R application in shell buffer"
  (interactive)
  (let ((R (concat "shiny::runApp('" default-directory "')")))
    (call-r-command `("-e" ,R "--no-save"))))

Next is function that return root of git repo (since my R package is also git repo):

(defun shell-line (command)
  "Function execute shell command and return the result as single line"
  (replace-regexp-in-string "\n" "" (shell-command-to-string command)))

The problem with git on Windows 10 in GNU Emacs (or because of shell-command-to-string function) is that path is in Unix format not in Windows format, so I need to fix the path to use it in my R calling script.

(defun git-root-repo ()
  "Function return root of the git repo"
  (interactive)
  (replace-regexp-in-string "/mnt/c/" "c:/" (shell-line "git rev-parse --show-toplevel")))

Now my final function that build the R package:

(defun build-r-package ()
  "Build R package using git root directory as path to R package"
  (interactive)
  (call-r-command `("CMD" "INSTALL" ,(git-root-repo))))

Missing function for finding buffer with same major mode can be found in my previous article Run shiny R application from Emacs.

, ,

Leave a comment

Better event type in Angular event handlers

I was learning Angular and Udemy video course as well as the official docs show this code:

export class KeyUpComponent_v1 {
  values = '';


  onKey(event: KeyboardEvent) { // with type info
    this.values += (<HTMLInputElement>event.target).value + ' | ';
  }
}

this looks much better in ReactJS with typescript, where event target have proper type:

onClick(event: MouseEvent<HTMLButtonEvent>) {

}

But this don’t work in Angular, you got Error: “Type ‘MouseEvent’ is not generic.”

So I’ve thought that I should try to create this type for Angular. And it look like this:

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

interface GenericEvent<T> extends Omit<Event, 'target'> {
    target: T;
}

You can use this type like this:

@Component({
    selector: 'app-input',
    template: '<input (input)="onInput($event)"/>'
})
export class InputComponent {
    value = '';
    onInput(event: GenericEvent<HTMLInputElement>) {
        this.value = event.target.value;
    }
}

NOTE: in this example I’ve used Event interface as base for GenericEvent, but for input event there is more specific type which is InputEvent.

And you can easily create event for each Event type in TypeScript (here are the list of Events interfaces, I’m not sure, but probably they all are types (interfaces) in TypeScript).

If you would like single type with two values, check this Stack Overflow post: Generic interface extending parameterized interface in TypeScript.

,

Leave a comment

Reload buffer when file changes in Emacs

I’ve started learning typescript and one of the cool feature of compiler is –watch options that recompile the file when it change it’s content. In Emacs if file is changed the buffer still contain old file and if you try to edit that file you’re ask if you really want to ed it that file because it change content.

It found that it would be nice to have reload when file changes, so I wrote this little bit of Emacs Lisp:

;; http://emacs.stackexchange.com/questions/22647/reload-single-file-in-every-window
(defun reload ()
  "Revert buffer, then restore previous position."
  (interactive)
  (let ((pt  (point)))
    (revert-buffer t t)
    (goto-char pt)))

;; two helpers to work with alists

(defun add-to-alist (symbol name value)
  "Add new pair to ALIST"
  (let* ((list (symbol-value symbol))
         (pair (assoc name list)))
    (if pair
        (setcdr pair value)
      (let ((pair (cons name value)))
        (if list
            (setf (symbol-value symbol) (cons pair list))
          (setf (symbol-value symbol) (cons pair nil)))))
    (symbol-value symbol)))

(defun remove-alist (symbol name)
  "Remove pair from ALIST"
  (let* ((list (symbol-value symbol))
         (pair (assoc name list)))
    (if pair
        (let ((ptr list))
          (if (eq (caar ptr) name)
              (setf (symbol-value symbol) '())
            (while ptr
              (if (eq (caadr ptr) name)
                  (progn
                    (setcdr ptr (cddr ptr))
                    (setq ptr nil))
                (setq ptr (cdr ptr))))
            list)))))

(require 'filenotify)

(setq file-watchers '())


(defun watch ()
  "Function watch file changes and reload the file from buffer"
  (interactive)
  (let* ((fname (buffer-file-name))
         (pair (assoc fname file-watchers)))
    (if pair
        (progn
          (file-notify-rm-watch (cdr pair))
          (remove-alist 'file-watchers descritor)))

    (let ((descriptor (file-notify-add-watch fname
                                             '(change)
                                             (lexical-let ((filename fname))
                                               (lambda (event)
                                                 (with-current-buffer (get-file-buffer filename)
                                                   (if (not (buffer-modified-p))
                                                       (progn
                                                         (message "update %s" filename)
                                                         (reload)))))))))
      (add-to-alist 'file-watchers fname descriptor))))

Then to watch the file You just need to invoke the function using M-x watch. The function will not reload the buffer if you have modifications. In that case you need to invoke reload function using M-x reload.

This will probably don’t work on windows but I’m not sure, here is documentation for file-notify-* functions.

,

3 Comments

Run shiny R application from Emacs

Right now I use Windows box for development at work and I use Emacs, but I needed to run RStudio to run the shiny application that I was working on. I though it would be nice to run shiny app from Emacs. On windows I was not able to run ansi-term but eshell was working.

Here is a function that run shiny app if the buffer you’re in is directory that contain server.R:

(defun shiny ()
  "run shiny R application in new shell buffer

  if there is displayed buffer that have shell it will use that window"
  (interactive)
  (let* ((R (concat "shiny::runApp('" default-directory "')"))
         (name "*shiny*")
         (new-buffer (get-buffer-create name))
         (script-proc-buffer
          (apply 'make-comint-in-buffer "script" new-buffer "R" nil `("-e" ,R)))
         (window (get-window-with-mode '(comint-mode eshell-mode)))
       (script-proc (get-buffer-process script-proc-buffer)))
    (if window
        (set-window-buffer window new-buffer)
      (switch-to-buffer-other-window new-buffer))))


(defun search-window-buffer (fn)
  "return first window for witch given function return non nil value"
  (let ((buffers (buffer-list))
        (value))
    (dolist (buffer buffers value)
      (let ((window (get-buffer-window buffer)))
        (if (and window (not value) (funcall fn buffer window))
            (setq value window)))))))

(defun get-window-with-mode (modes)
  "return window with given major modes"
  (search-window-buffer (lambda (buff window)
                        ((let ((mode (with-current-buffer buffer major-mode)))
                          (member mode modes)))))


I’ve needed to use sentinels because If I run simple eshell command it was freezing Emacs and I need to press C-g to cancel the command, it din’t kill R but it was not very good solution.

I’ve also need to update my switch to other major mode buffer, because I was using Eshell that had eshell-mode and my new shiny buffer had comint-mode, I wanted those buffers it to be treated as the same. Above I’ve defined two functions for searching windows because I was using eshell and I wanted to have R from shiny run in the same window. If you’re using ansi-term (on windows it don’t work) you can check it’s major mode and add it to the list of modes in call to get-window-with-mode.

Below is the code for switching to other buffer with same mode (it’s should be common maybe), using C-M-tab and C-tab.

(setq same-mode-alist '((eshell-mode comint-mode) (comint-mode eshell-mode)))

;; SAME BUFFER SWITCH
(defun buffer-same-mode (change-buffer-fun)
  "execute function for next buffer with the same major mode
  or mode on the list in same-mode-alist variable"
  (let ((current-mode major-mode)
        (next-mode nil))
    (while (not (or (eq next-mode current-mode)
                    (member next-mode (cdr (assoc current-mode same-mode-alist)))))
      (funcall change-buffer-fun)
      (setq next-mode major-mode))))

(defun previous-buffer-same-mode ()
  "switch to previous buffer with same mode"
  (interactive)
  (buffer-same-mode #'previous-buffer))

(defun next-buffer-same-mode ()
  "switch to next buffer with same mode"
  (interactive)
  (buffer-same-mode #'next-buffer))

(global-set-key [C-M-tab] 'previous-buffer-same-mode)
(global-set-key [C-tab] 'next-buffer-same-mode)

,

1 Comment

Show code coverage from jest framework in emacs

I recently switched from jasmine/istanbul to jest framework for my project jQuery Terminal and I’ve got coverage drop from 80-81% to about 69% with some update of the code and commented out code that I was working on.

So I thought it would be cool to highlight the lines that where covered and not covered by tests and since I use emacs as my editor I thought that I write a function that will do that.

Here it is:

(defun root-git-repo ()
  (interactive)
  (replace-regexp-in-string "\n"
                            ""
                            (shell-command-to-string "git rev-parse --show-toplevel")))

(defun line-pos-at-line (line)
  (interactive)
  (save-excursion
    (goto-line line)
    (line-beginning-position)))

(defun coverage-mark-buffer ()
  (interactive)
  (let* ((dir (root-git-repo))
         (json-object-type 'hash-table)
         (json-array-type 'list)
         (json-key-type 'string)
         (json (json-read-file (concat dir "/coverage/coverage-final.json")))
         (filename (buffer-file-name (current-buffer)))
         (coverage (gethash filename json))
         (statments (gethash "statementMap" coverage)))
    (save-excursion
      (maphash (lambda (key value)
                 (let* ((statment (gethash key statments))
                        (start (gethash "start" statment))
                        (end (gethash "end" statment))
                        (start-line-pos (line-pos-at-line (gethash "line" start)))
                        (start-pos (+ start-line-pos (gethash "column" start)))
                        (end-line-pos (line-pos-at-line (gethash "line" start)))
                        (end-pos (+ end-line-pos (gethash "column" end)))
                        (color (if (= value 0) "dark red" "dark green"))
                        (face `((t (:background ,color)))))
                    (hlt-highlight-region start-pos end-pos face)))
               (gethash "s" coverage)))))

The function is using hlt-highlight-region from highlight.el by Drew Adams.

The function don’t check if coverage file exists. It assume that you’re opening from from git repo and that coverage file is in coverage directory (default for jest) in git root.

The function is quite slow, and it need to process a lot, if the file is big. You can see how it look like in this page, generated by Emacs library htmlize.

If you want to clear the buffer you can use this function:

(defun coverage-clear-buffer ()
  (interactive)
  (save-excursion
    (end-of-buffer)
    (hlt-unhighlight-region 0 (point))))

Clear is much faster.

If you’re iterested in code coverage in Emacs you can take a look at jest-coverage minor mode that I’ve created based on this solution.

, , ,

Leave a comment

How to create Web Server from Browser

In my GIT Web Terminal I use BrowserFS to write files (it’s required by isomorphic-git that I use to create git interface in browsers).
BrowserFS is implementation of node fs module but for browsers, it use few types of storage, I use indexedDB same as example for isomorphic-git.

I thought that i would be cool to edit the project itself and be able to view the files when I edit them in the browser (before I commit), like they where serve from web server. And it turn out it’s possible with Service Worker since you can access IndexedDB from that worker and you can create HTTP response from string or from arrayBuffer (BrowserFS is returning arrayBuffer from its readFile function).

Here is the code for service worker that show pages and directory listing:

self.addEventListener('install', function(evt) {
    self.skipWaiting();
    self.importScripts('https://cdn.jsdelivr.net/npm/browserfs');
    BrowserFS.configure({ fs: 'IndexedDB', options: {} }, function (err) {
        if (err) {
            console.log(err);
        } else {
            self.fs = BrowserFS.BFSRequire('fs');
            self.path = BrowserFS.BFSRequire('path');
        }
    });
});

self.addEventListener('fetch', function (event) {
    event.respondWith(new Promise(function(resolve, reject) {
        function sendFile(path) {
            fs.readFile(path, function(err, buffer) {
                if (err) {
                    err.fn = 'readFile(' + path + ')';
                    return reject(err);
                }
                resolve(new Response(buffer));
            });
        }
        var url = event.request.url;
        var m = url.match(/__browserfs__(.*)/);
        function redirect_dir() {
            return resolve(Response.redirect(url + '/', 301));
        }
        if (m && self.fs) {
            var path = m[1];
            if (path === '') {
                return redirect_dir();
            }
            console.log('serving ' + path + ' from browserfs');
            fs.stat(path, function(err, stat) {
                if (err) {
                    return resolve(textResponse(error404(path)));
                }
                if (stat.isFile()) {
                    sendFile(path);
                } else if (stat.isDirectory()) {
                    if (path.substr(-1, 1) !== '/') {
                        return redirect_dir();
                    }
                    fs.readdir(path, function(err, list) {
                        if (err) {
                            err.fn = 'readdir(' + path + ')';
                            return reject(err);
                        }
                        var len = list.length;
                        if (list.includes('index.html')) {
                            sendFile(path + '/index.html');
                        } else {
                            var output = [
                                '',
                                '',
                                '',
                                '<h1>BrowserFS</h1>',
                                '<ul>'
                            ];
                            if (path.match(/^\/(.*\/)/)) {
                                output.push('<li><a href="..">..</a></li>');
                            }
                            (function loop() {
                                var file = list.shift();
                                if (!file) {
                                    output = output.concat(['</ul>', '', '']);
                                    return resolve(textResponse(output.join('\n')));
                                }
                                fs.stat(path + '/' + file, function(err, stat) {
                                    if (err) {
                                        err.fn = 'stat(' + path + '/' + file + ')';
                                        return reject(err);
                                    }
                                    var name = file + (stat.isDirectory() ? '/' : '');
                                    output.push('<li><a href="' + name + '">' + name + '</a></li>');
                                    loop();
                                });
                            })();
                        }
                    });
                }
            });
        } else {
            fetch(event.request).then(resolve).catch(reject);
        }
    }));
});
function textResponse(string) {
    var blob = new Blob([string], {
        type: 'text/html'
    });
    return new Response(blob);
}

function error404(path) {
    var output = [
        '',
        '',
        '',
        '<h1>404 File Not Found</h1>',
        `File ${path} not found in browserfs`,
        '',
        ''
    ];
    return output.join('\n');
}

Service worker is using __browserfs__ marker to distinguish normal url from urls that are from BrowserFS/IndexedDB. Everything after it it’s serve from BrowserFS. So if you write file foo you can access it using __browserfs__/foo. Here is the code sample that will create a file using browserFS:

fs.writeFile('/foo', 'hello world', function(err) {
   if (err) {
     console.log('Error write file');
   }
});

You can see how this work in my GIT Web Terminal just clone any repo (best is the one that have directories) and view files with url https://jcubic.github.io/git/__browserfs__/repo/path/to/file.

, ,

1 Comment

How to create D3 Plugin

I was learning D3 and wanted to write plugin attrs, that will allow to use object to set attributes on svg DOM nodes. It seems that this functionality was in D3 but was removed.

I was searching and was not able to fine how to create the plugins, but then I look at source code for d3 transition (it’s easier to search bundle file than original files on github).

And at the end, there was code that I’ve needed to use. That’s what I thought it require to add to prototype.

So here is my attrs plugin:

d3.selection.prototype.attrs = function(attrs) {
  this.each(function(d, i) {
    var element = d3.select(this);
    Object.keys(attrs).forEach((key) => {
      element.attr(key, attrs[key]);
    });
  });
  return this;
};

You can use it like normal attr:

var g = d3.select('body')
  .append('svg')
  .attrs({width: 200, height: 200})
  .append('rect').attrs({
    x: 50,
    y: 50,
    width: 100,
    height: 100,
    stroke: 'rgb(255, 100, 100)',
    'stroke-width': 10,
    fill: 'black'
  });

It works the same as jQuery plugins.

, ,

Leave a comment

%d bloggers like this: