RSS Feed

Best ever programmer text editor: Emacs


I was using jEdit. And once willing to change to, so called modern text editor, Atom Text Editor. Then I did some comparisons among the text editors. At the end, now my primary text editor for coding is Emacs.

Emacs requires some time to learn and practise. But at the end, I love it too much. It is so powerful, no other text editor to compare with it. But the primary usage is for coding.

What are the advantages? It has various powerful addons (packages). It is highly customisable. It can work in command-line, that means you can use it over the SSH. (But normally I use Vim instead.) Like Vim, it can browse a directory. It can also perform diff and merge (but I use meld usually). It can work with gdb for debugging. It has syntax highlighting on different languages. It can perform different indentation based on various languages. Syntax highlighting can work on web development which combines JavaScript, CSS, HTML, and even PHP (using “web mode”). It can save the opened files as a project, so that you can work on multiple projects. It can split the views vertically and horizontally, basically unlimited splits. If you want, you can play Tetris in it. It can be used as window manager too.

There are several modes that are interesting. I suggest to know these modes:

  • dired – Directory browsing
  • ibuffer – List and manage opened files
  • eshell – Emacs shell, like bash
  • ielm – Inferior Emacs Lisp Mode. Interactive Lisp environment
  • w3m – w3m web browser, requires package installation.
  • eww – Default web browser in Emacs, but I found it is difficult to use compared to w3m

Customising Emacs to fit your pattern requires some time.

Just share my .emacs file,

(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(buffers-menu-max-size 10)
 '(column-number-mode 1)
 '(ediff-split-window-function (quote split-window-horizontally))
 '(inhibit-startup-screen t)
 '(show-paren-mode t)
 '(tool-bar-mode nil))
(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(default ((t (:family "DejaVu Sans Mono" :foundry "unknown" :slant normal :weight normal :height 113 :width normal)))))


;; Emacs default setting
(desktop-save-mode 1)
(global-linum-mode 1)
(savehist-mode 1)
(global-auto-revert-mode t)
(setq column-number-mode 1)
(delete-selection-mode 1)

(setq backup-inhibited t)
(setq auto-save-default nil)
(setq mouse-drag-copy-region nil)


(setq-default indent-tabs-mode nil) ;;Disable indent tabs globally
;;Create my own function
(defun my-toggle-tab ()
  (interactive)
  (if (default-value indent-tabs-mode)
      (progn
        (message "Space indent")
        (setq indent-tabs-mode nil)
        )
    (progn
      (message "Tab indent")
      (setq indent-tabs-mode t)
      )
    )
  )
(global-set-key (kbd "C-x C-t") 'my-toggle-tab)


;; Very annoying that override the content with delete word http://stackoverflow.com/questions/6133799/delete-a-word-without-adding-it-to-the-kill-ring-in-emacs
(defun backward-delete-word (arg)
  "Delete characters backward until encountering the beginning of a word.
With argument ARG, do this that many times."
  (interactive "p")
  (delete-region (point) (progn (backward-word arg) (point))))
(global-set-key (kbd "<M-backspace>") 'backward-delete-word)



;; Change font for Chinese characters
(set-fontset-font t 'han (font-spec :family "WenQuanYi Zen Hei Mono"))



;; mouse from http://www.emacswiki.org/emacs/SmoothScrolling
(setq mouse-wheel-scroll-amount '(4 ((shift) . 1))) ;; one line at a time
(setq mouse-wheel-progressive-speed nil) ;; don't accelerate scrolling
(setq mouse-wheel-follow-mouse 't) ;; scroll window under mouse
(setq scroll-step 1) ;; keyboard scroll one line at a time

;; Delete whitespace when save
(add-hook 'before-save-hook 'delete-trailing-whitespace)


;; White space mode
(global-whitespace-mode 1)
(autoload 'whitespace-global-mode "whitespace"
  "Toggle whitespace visualization." t
  (setq whitespace-style (quote (face spaces tabs space-mark tab-mark)))
  )
(autoload 'whitespace-toggle-options "whitespace"
  "Toggle load `whitespace-mode' options." t)


;; Add MELPA
(require 'package)
(add-to-list 'package-archives
	     '("melpa" . "https://melpa.org/packages/"))
(when (< emacs-major-version 24)
  (add-to-list 'package-archives '("gnu" . "http://elpa.gnu.org/packages/")))
(package-initialize)


;;Recent file
(require 'recentf)
(recentf-mode 1)
(setq recentf-max-menu-items 15)
(global-set-key (kbd "C-x C-r") 'recentf-open-files)


;; Load undo-tree and set the undo/redo hotkey
(require 'undo-tree)
(global-undo-tree-mode 1)
(global-set-key (kbd "C-z") 'undo-tree-undo)
(global-set-key (kbd "C-S-z") 'undo-tree-redo)



;; Smooth scroll
(require 'smooth-scroll)
(smooth-scroll-mode 1)


;; Enable auto-complete
(require 'auto-complete)
(global-auto-complete-mode 1)


;; Enable hideshowvis to fold and expand the code
;;(require 'hideshowvis)
;;(hideshowvis-minor-mode 1)


;; Make web-mode to indent with 2 spaces, https://emacs.stackexchange.com/questions/2355/make-web-mode-always-indent-with-spaces
(require 'web-mode)
(defun my-web-mode-hook ()
  "Hooks for Web mode."
  (setq indent-tabs-mode nil)
  (setq tab-width 4)
  (setq web-mode-markup-indent-offset 2)
  (setq web-mode-css-indent-offset 2)
  (setq web-mode-code-indent-offset 2)
  (setq web-mode-style-padding 0)
  (setq web-mode-script-padding 0)
  (setq web-mode-enable-css-colorization t)
)
(add-hook 'web-mode-hook  'my-web-mode-hook)



;; Disable csharp-mode tab
(require 'csharp-mode)
(defun my-csharp-mode-fn ()
  "function that runs when csharp-mode is initialized for a buffer."
  (turn-on-auto-revert-mode)
  (setq indent-tabs-mode nil)
)
(add-hook  'csharp-mode-hook 'my-csharp-mode-fn t)


;;Auto js2-mode
(autoload 'js2-mode "js2-mode.el" nil t)
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))


;;HTML
(autoload 'web-mode "web-mode.el" nil t)
(add-to-list 'auto-mode-alist '("\\.html$" . web-mode))
;; (add-to-list 'auto-mode-alist '("\\.php$" . web-mode))

(autoload 'pkgbuild-mode "pkgbuild-mode.el" "PKGBUILD mode." t)
(setq auto-mode-alist (append '(("/PKGBUILD$" . pkgbuild-mode)) auto-mode-alist))

(require 'w3m-load)
(setq w3m-default-display-inline-images t)


(require 'desktop+) ;;Use the desktop+

;; (autoload 'php-mode "php-mode.el" "Php mode." t)
;; (setq auto-mode-alist (append '(("/*.\.php[345]?$" . php-mode)) auto-mode-alist))
;; (autoload 'python-mode "python-mode.el" "Python mode." t)
;; (setq auto-mode-alist (append '(("/*.\.py$" . python-mode)) auto-mode-alist))

It would be better if you learn Emacs from the beginning and try to adapt the default key bindings (hotkeys). Because, if you replace some of the hotkeys with the ones you are used to, you may miss the default key binding power. No more Ctrl+X, C, or V for cut, copy, and paste. Just learn Emacs and customise it.

One more thing, I was looking for folding (collapse and expand) feature. But failed to find one. Yet, just use the key binding C-M-p and C-M-n are enough to fit my demand.

The following is the video which I screencasted with SimpleScreenRecorder and edited by Blender.

Data structure and algorithm


As a computer science lecturer (though I am from cognitive science background, and even labelled as NOT from computer science, 士可杀,不可辱!), I focus on the fundamental knowledge and experience. I focus on C/C++ language on my students, because only have good fundamental knowledge and skills, then they can survive with the evolving technology once they graduated. For example, Flash was popular technology, yet now it is dying. Those who know Flash only, have to learn new technology. Without fundamental skill, how to cope with the new technologies that emerge everyday? Know the root, then you can get any leaf.

So, I gave my students an assignment. The assignment requires them to write a program that can

  • Read a text file as a map, with binary information in the map, block or space. Block does not allow to move; the space allows to move.
  • Find the route from upper left to the lower right (assuming that there is at least one route in the map file.)
  • Show the route that goes from upper left to lower right through the space.

To write a program, the first thing is to design the data structure that can hold the input/output data. Only with the good data structure, then the algorithms will emerge automatically.

I personally spent around 3 hours to write the program using C++ language, but not object oriented and omitted the STL. No object oriented involved, but only struct. The solution involves 2D array, linked list, tree (ADT) and tree traversal, and stack with doubly linked list.

The file is read line by line, and converted into 2D array. Then using the 2D array, convert this 2D map with blocks and spaces into a tree data structure. The spaces are connected as the tree nodes, the blocks are ignored. Each node has an (x, y)-coordinate. Once the tree data structure is completed, then I wrote a depth first search (DFS) as a tree traversal, start from the upper left, and target the lower right. However, because it is a DFS, it will try all branches in the search tree. So, I have to use a stack (using doubly linked list) to store the route that straight to the destination. Finally, the route in the stack is printed.

No GUI, because inside-out is important, just like a pretty apple with rotten content is good for nothing. What I focus is the inner quality (attitude, hardworking, problem solving, etc), not the flattering or boasting. Since I am a Catholic, Chinese, cognitive science student, programmer, and INTJ personality (if you don’t know what is INTJ, please go to google it), when it is true, I say true; when it is false, I say false; when I don’t know, I say I don’t know. All the BS reserved for those BSers. Since I am a lecturer, it is my responsibility to optimise my lecturing function to guide the students in their studies. It is a shame for those academic murderers who exploit the students in order to get their own fame, get the research grant, and plagiarise the students’ work to publish their own research papers.

So, the coding I wrote also demonstrates the usage of pointer (computer science students MUST know), dynamic memory allocation, and recursive function (important in FP).

#include <cstdio>
#include <cstring>
#include <cstdlib>

struct MapNode {
  MapNode *up;
  MapNode *down;
  MapNode *left;
  MapNode *right;
  int data;
  int x;
  int y;
  int visited;
};

/**
 * This is just like the OOP object constructor.
 */
MapNode* mapNodeCreate(int x, int y, int data) {
  MapNode *n = new MapNode;
  n->up = NULL;
  n->down = NULL;
  n->left = NULL;
  n->right = NULL;
  n->x = x;
  n->y = y;
  n->data = data;
  n->visited = 0;
  return n;
}

/**
 * The following stack design is like this,
 * the Stack is a container of the StackNode*.
 * The StackNode contains MapNode*
 * Therefore, using the Stack ADT, we can push and pop the StackNode.
 * Since the StackNode is a doubly linked list, at the same time it holds the MapNode* (pointer)
 */

struct StackNode {
  MapNode *mapNode;
  StackNode *next;
  StackNode *prev;
};


StackNode* stackNode(MapNode *mapNode) {
  StackNode *n = new StackNode;
  n->mapNode = mapNode;
  n->next = NULL;
  n->prev = NULL;
  return n;
}

/**
 * So, a Stack contains several StackNode*.
 */
struct Stack {
  StackNode *head;
  StackNode *tail;
};

Stack* stackCreate() {
  Stack *s = new Stack;
  s->head = NULL;
  s->tail = NULL;
  return s;
}


void stackPush(Stack *s, StackNode *n) {
  if(!s->head) { //First item
    s->head = n;
    s->tail = n;
  }
  else { //If there is a node
    s->tail->next = n;
    n->prev = s->tail;
    s->tail = s->tail->next;
    //Make sure it is the last
    s->tail->next = NULL;
  }
}

int stackSize(Stack *s) {
  int size = 0;
  StackNode *curr = s->head;
  while(curr) {
    size++;
    curr = curr->next;
  }
  return size;
}

StackNode* stackPop(Stack *s) {
  StackNode *n = s->tail;
  s->tail = s->tail->prev;
  s->tail->next = NULL;
  return n;
}

void stackPrint(Stack *s) {
  StackNode *curr = s->head;
  while(curr) {
    printf("(%d, %d)\n", curr->mapNode->x, curr->mapNode->y);
    curr = curr->next;
  }
}

MapNode **list; //For storing the nodes, then delete them at the end
Stack *stack = stackCreate(); //For storing the coordinates, default will head NULL and tail NULL


/**
 * In order to solve this, this is very complicated. Firstly, I used
 * a variable depth to check when is the push and pop are appropriate,
 * As a result, convert the depth++ to the push and depth-- to the pop
 * to make sure that only correct nodes are stored, and incorrect nodes will be popped.
 * So, this function is traversing all the route, and push the correct route to the stack.
 */
void mapTraverse(MapNode *node, int x, int y, bool *stop) {
  if(!*stop) //Push only if still searching
    stackPush(stack, stackNode(node));

  if(*stop) {
    return;
  }
  if(!node) {
    stackPop(stack);
    return;
  }
  if(node->visited) {
    stackPop(stack);
    return;
  }

  if(node->x == x && node->y == y) {
    *stop = true;
    printf("(%d, %d) Found!!\n", node->x, node->y);
    return;
  }
  node->visited = 1; //mark visited
  printf("(%d, %d), ", node->x, node->y);
  mapTraverse(node->left, x, y, stop);
  mapTraverse(node->up, x, y, stop);
  mapTraverse(node->right, x, y, stop);
  mapTraverse(node->down, x, y, stop);
  if(!*stop) { //Do not pop if founded.
    stackPop(stack);
  }
}

void arrPrint(int *arr, int w, int h) {
  for(int i=0;i<h;i++) {
    for(int j=0;j<w;j++) {
      printf("%d ", arr[i*w + j]);
    }
    printf("\n");
  }
  printf("\n");
}


/**
 * The text file is the binary (1 or 0) content.
 * @param w is the pointer to the width (output)
 * @param h is the pointer to the height (output)
 * @return a pointer of integer for the map.
 */
int* readFileToArray(const char* filename, int *w, int *h) {
  FILE *fp = fopen(filename, "r");

  if(!fp) {
    fprintf(stderr, "Failed to open file\n");
    return NULL;
  }

  char buffer[256];

  //This method (supposed) only applicable for the text file with "\n" (Unix file),
  // not the "\r\n" or "\n\r" (Windows or MacOSX)
  //Get the map dimension first.
  fgets(buffer, 255, fp);
  int width = strlen(buffer) -1;

  //Go to the end of the file
  fseek(fp, 0, SEEK_END);
  int height = ftell(fp) / (width+1);

  printf("width: %d\theight: %d\n", width, height);

  //Go back to the beginning of the file
  fseek(fp, 0, SEEK_SET);

  //Create an array
  int *arr = new int[width * height];
  int *cursor = arr;

  while(fgets(buffer, 255, fp)) {
    buffer[strlen(buffer) -1 ] = 0;
    for(int i=0;i<strlen(buffer);i++) {
      *cursor = buffer[i] - '0'; //Convert the character to the value
      cursor++;
    }
  }
  fclose(fp);

  //Get the width and height
  *w = width;
  *h = height;

  return arr;
}

MapNode* arrToMap(int *arr, int width, int height) {
  //Use an array to store the map node
  list = new MapNode*[width * height]; //This is the syntax that creates an array of pointer (with "*") after the data type.

  for(int j=0;j<height;j++) {
    for(int i=0;i<width;i++) {
      //Create the node
      MapNode *node = mapNodeCreate(i, j, arr[j*width +i]);
      list[j*width +i] = node;
    }
  }

  //Check the connectedness horizontally
  for(int i=0;i<height;i++) {
    for(int j=0;j<width -1;j++) {
      if(arr[i*width+j] == 1 && arr[i*width +j+1] ==1) {
        list[i*width+j]->right = list[i*width +j+1];
        list[i*width+j+1]->left = list[i*width+j];
      }
    }
  }

  //Check the connectedness vertically
  for(int i=0;i<height-1;i++) {
    for(int j=0;j<width;j++) {
      if(arr[i*width+j] == 1 && arr[(i+1)*width +j] ==1) {
        list[i*width+j]->down = list[(i+1)*width +j];
        list[(i+1)*width+j]->up = list[i*width+j];
      }
    }
  }
  MapNode *root = list[0];

  return root; //Return the first node
}


int main(int argc, char **argv) {
  if(argc < 2) {
    printf("Usage: %s map.txt\n", argv[0]);
    return 1;
  }

  int width, height;
  int *arrMap;
  arrMap = readFileToArray(argv[1], &width, &height);

  arrPrint(arrMap, width, height);

  MapNode* mapRoot = arrToMap(arrMap, width, height);


  //Traverse the nodes;
  bool stop = false; //use this to control so that once found, need not to perform recursive search
  mapTraverse(mapRoot, width-1, height-1, &stop);

  printf("Stack size %d\n", stackSize(stack));

  stackPrint(stack);

  delete arrMap;

  //Delete all the nodes
  for(int i=0;i<width * height;i++) {
    delete list[i];
  }

  delete stack;

  return 0;
}

The sample input text file,

10000000000000000000
10000000111111111100
10000000100000100000
10000000100000100000
11111111111111111110
00000100000000100000
00000100000000111110
00000100000000000000
11111100000000000000
00000111111111100000
00000100001000000000
00000100001000000000
00000000001111111100
01110000000000000110
01110000000000000011

And this is the output

width: 20	height: 15
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 
1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 
1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 
0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 
0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1 1 0 
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 
0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 
0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 
0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 

(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 4), (2, 4), (3, 4), (4, 4), (5, 4), (6, 4), (7, 4), (8, 4), (8, 3), (8, 2), (8, 1), (9, 1), (10, 1), (11, 1), (12, 1), (13, 1), (14, 1), (15, 1), (16, 1), (17, 1), (14, 2), (14, 3), (14, 4), (13, 4), (12, 4), (11, 4), (10, 4), (9, 4), (15, 4), (16, 4), (17, 4), (18, 4), (14, 5), (14, 6), (15, 6), (16, 6), (17, 6), (18, 6), (5, 5), (5, 6), (5, 7), (5, 8), (4, 8), (3, 8), (2, 8), (1, 8), (0, 8), (5, 9), (6, 9), (7, 9), (8, 9), (9, 9), (10, 9), (11, 9), (12, 9), (13, 9), (14, 9), (10, 10), (10, 11), (10, 12), (11, 12), (12, 12), (13, 12), (14, 12), (15, 12), (16, 12), (17, 12), (17, 13), (18, 13), (18, 14), (19, 14) Found!!
Stack size 34
(0, 0)
(0, 1)
(0, 2)
(0, 3)
(0, 4)
(1, 4)
(2, 4)
(3, 4)
(4, 4)
(5, 4)
(5, 5)
(5, 6)
(5, 7)
(5, 8)
(5, 9)
(6, 9)
(7, 9)
(8, 9)
(9, 9)
(10, 9)
(10, 10)
(10, 11)
(10, 12)
(11, 12)
(12, 12)
(13, 12)
(14, 12)
(15, 12)
(16, 12)
(17, 12)
(17, 13)
(18, 13)
(18, 14)
(19, 14)

 

Xfce4, LXDE, and Openbox


What I need is performance, eye candy is optional.

My primary desktop environment is Xfce, as it is more lightweight than GNOME, KDE, or Cinnamon (Mate is out of my choice), yet it has more goodies (plugins) than LXDE. But due to my 4-year-old laptop, I found that LXDE has better performance than Xfce significantly. I can run multiple heavy applications at the same time, especially Firefox and Chromium. Xfce performance drops when I run both applications simultaneously. Switching between applications is slower. If running with Skype at the same time, and doing some development testing, the performance drops drastically.

LXDE is even more lightweight than Xfce. That is why I used LXDE. The only drawback of LXDE is that it does not allow me to zoom the screen with Alt+Mouse Scroll. This is a crucial feature I need as a lecturer. In order to gain a better speed, I also have to sacrifice the wallpaper auto changing as in Xfce. Furthermore, configuring the LXDE is a little troublesome. Since LXDE is using Openbox as window manager, a lot of configurations depend on the Openbox.

Openbox configuration

To configure the LXDE Openbox, we can use the obconf to configure. It is actually editing the ~/.config/openbox/lxde-rc.xml.

obconf also works on Openbox (window manager only). The corresponding file is ~/.config/openbox/rc.xml.

Hotkey configuration

LXDE hotkeys are depending on the Openbox too. We can use the obkey to configure the hotkeys. It is also editing the ~/.config/openbox/lxde-rc.xml or rc.xml.

Openbox right-click context menu

LXDE has its own panel (lxpanel). It allows to show (mostly) all the applications in the menu. However, if we right-click Openbox desktop area, the context menu does not show the installed applications. The application menu in the Openbox is actually written in the ~/.config/openbox/menu.xml. The skeleton file contains the hard coded applications.

There are several ways to show the menu items dynamically based on the installed applications. I personally use openbox-xdgmenu by adding something like this to the menu.xml,

<menu execute="openbox-xdgmenu /etc/xdg/menus/lxde-applications.menu" id="desktop-app-menu" label="Applications"/>

menu.xml is also used by Openbox without running the LXDE. That means, if a user login with Openbox window manager instead of LXDE, it will use the same menu.xml.

However, this can be changed by editing the lxde-rc.xml (LXDE) or rc.xml (Openbox window manager only) to load specific menu XML file. As a result, we are allowed to have different menu.xml files, one for LXDE and one for Openbox (window manager only).

Autostart

Autostart is quite complicated. If using LXDE, Xfce, or Openbox, the application desktop files in the ~/.config/autostart will be launched once login. They can also be disabled.

However, LXDE also allows autostart through ~/.config/lxsession/LXDE/autostart, where the LXDE is the default profile name. The autostart file is not exactly a shell script, but we can add the commands in this autostart file.

Though LXDE is based on Openbox, it does not use ~/.config/openbox/autostart file. If we login with Openbox window manager only, then ~/.config/openbox/autostart will be sourced (called) instead. This autostart file is just a shell script. As a result, we can use control structure like if-else. In order to run a batch of commands immediately, we can use the “&” to run the commands in the background.

There is another thing worth to know. If our display manager is LXDM or LightDM, it will source the ~/.xprofile. However, if we write our commands in the .xprofile, (I think) the commands will called before the DE is totally loaded. Therefore, the command like “compton” will not affect the Openbox. (Compton is an X window compositor, so that the Openbox will become compositing window manager.)

Openbox applications

Since Openbox is just a window manager, if we login with Openbox window manager only, there is no panel, wallpaper, volume control, etc. Therefore, we have to install the packages by our own. Besides that, Openbox does not handle graphical logout. However, we can install oblogout and add it to the Openbox menu.

I personally use the tint2 as the panel, feh for the wallpaper for both Openbox and LxDE (since I don’t use PCManFM), volumeicon for controlling the volume, compton to composite the window, and xscreensaver for screen saver. tint2 has the battery indicator and date time indicator. So, this is how my Openbox look.

Openbox with Tint2

Openbox with Tint2

 

Tab vs space


I was using tab for indentation in coding, instead of spaces. Because I feel that one byte of tab is better than four bytes of space. It produces smaller file size.

However, the problems become prominent in the following circumstances.

  • Viewing different languages may require different indentation width. XML and HTML may use 2 characters width, other languages may use 4 characters width. Changing the tab width from the setting frequently is inconvenient.
  • Editing source code with different developers and using different text editors will produce source code with both tab and space indentation. As a result, the indentation becomes inconsistent.
  • Emacs problem. If the Emacs tab width is set to 8 characters, but the source code indentation is 4, this produces both tab and space indentation at the same line, for example, 3 indents (12 characters width) produce 1 tab with 4 spaces. Oh dear, I always show the whitespace and tab marks in the editor. The ugliness disturbs me.
  • Git diff view. If using Git GUI, it will highlight the tab indentation when the pervious line is a space indentation.

So, in the cases above, space indentation becomes handy. Though different developers use different text editor may produce different width of space indentation, with space indentation will produce better output than tab indentation.

But not all text editors support auto-indent feature, and not all text editors support tab to space indentation. So, I have to choose the text editor that meets my need.

I use jEdit and recently use Emacs. jEdit allows to convert the tab to space easily. But jEdit does not have the fixed indentation like Emacs. Emacs has the “major modes”, based on the major modes, the source codes are syntax highlighted differently and the indentation will be arranged differently.

Just a short comparison between Emacs and Atom Text Editor. Emacs is a very old text editor; Atom is modern. Both are highly customisable. Atom has a lot of packages available; Emacs has more than enough packages available. But I choose Emacs over modern editor like Atom, because Emacs has various powerful modes available. It is not only an editor, but can also be a debugger, or even IDE. Based on my experience, Emacs auto-indentation on the complex HTML with JavaScript and CSS works better than Atom.

As a result, I choose space indentation over tab indentation, as it is more consistent and text editor independent.

Ubuntu with BCM43228


 

My campus lab has the Dell desktops. I am not sure the model, but the network devices are Broadcom BCM43228. As a result, after installation of the Ubuntu (they were not installed by me), Ubuntu cannot get WiFi connection to online.

Since my student mentioned that Windows can use the ethernet cable to share the wireless network, I asked him to help to share the wireless network from Windows on the other Dell desktop, and connect to the target Dell desktop.

This step works.

Next, I followed this Q and A post, just followed exactly all the commands there. Then reboot.

Yes! It works. Now, my students can test Ubuntu.

Statistics and functional programming languages


Recently, I feel fervent to learn functional programming, because i) (in my opinion), it will become a trend, and ii) the interpreter can be used as an advanced calculator.

Since I am teaching Statistics, I want to do some calculation of the normal distribution probability.

Before I begin, I need to mention, in order to calculate the normal distribution probability something like P(x < X), this can be done by using a spreadsheet software with NORMDIST() and NORM.INV() for the inverse of the former function.

Spreadsheet is good for calculation, but not good as a calculator. My primary calculator is SpeedCrunch, which allows entering expression. But the drawback of SpeedCrunch is the lack of statistical functions.

Therefore, the functional programming comes to my mind.

Firstly, let me introduce the usage of Python. Make sure SciPy is installed. Run the Python interpreter,

from scipy.stats import norm
norm.cdf(my_value)
norm.ppf(my_probability)

So, the two functions are norm.cdf() (cumulative distribution function) and norm.ppf() (percent point function).

Now, let me introduce the usage of R language.

pnorm(my_value)
qnorm(my_probability)

R language is used for statistics, thus, no further module or library is required.

Both Python and R languages are not pure functional programmings. I wanted to try Emacs Lisp, but the arithmetic syntax is not convenient. The syntax is using Polish notation. In order to perform arithmetic calculation,

(* 2 (+ 3 6))

Therefore, I tried the pure functional programming language, that is, Haskell.

In order to calculate the normal distribution probability, the Statistics module is required. After installation,

import Statistics.Distribution
import Statistics.Distribution.Normal
let d = normalDistr 0 1
cumulative d 0
quantile d 0.5

“normalDistr 0 1” is to create a normal distribution with mean 0 and standard deviation 1. Then “cumulative d 0” is the calculation of CDF (cumulative distribution function), which produces 0.5. And “quantile” is the inverse function of CDF.

So, enjoy the functional programming in mathematics and statistics.

Xfce4 Power Manager, NVIDIA, Nouveau backlight issue


Recently I move back to use my (around) 4 years old laptop, HP Pavilion dv3. It has NVIDIA graphic card. But since I (re-)installed Arch Linux 64 bit on it, I failed to run the X11 with the proprietary NVIDIA driver. As a result, I used the Nouveau module instead. Then, I tried several times and finally successfully run the X11 with NVIDIA driver.

To use the Nouveau module, in the mkinitcpio.conf, we have to add in “nouveau” module, then build the initramfs (refer to wiki page). And use the “Xorg -configure” to generate the xorg.conf.

But in order to use the NVIDIA driver, firstly, has to identify the NVIDIA graphic card and download the related drivers. Secondly, since I am using 64 bit, but also running 32 bit packages, so I have to install all the corresponding lib32 NVIDIA packages. Moreover, the nvidia*-libgl are conflicted to mesa-libgl, which is used by Nouveau. After installing NVIDIA, use “nvidia-xconfig” to generate the xorg.conf.

We can also disable the splash screen (logo) when starting the X11, by adding

Options "NoLogo" "1"

in the “Device” section in the xorg.conf.

Then after using the NVIDIA, I face a serious problem, that is the xrandr (in fact I am usign ARandR) cannot change the screen resolution. This is troublesome as I need to make the changes towards the projector (2nd screen) frequently, such as two screens (left screen and right screen), laptop only (disable the projector), or clone (both laptop and the projector share the same screen). With the NVIDIA, xrandr cannot detect other resolutions, consequently I cannot make clone of the screen. So, I decided to use back Nouveau.

However, I have another serious problem with Nouveau module, that is, adjusting the backlight brightness (screen brightness). When I use xbacklight, it shows

No outputs have backlight property

I cannot adjust the backlight brightness using the usual keyboard key with Xfce4 Power Manager. Some forums stated that adding “acpi_backlight=xxxx” to the kernel parameter. But none of them works.

In my /sys/class/backlight, there are acpi_video0 and nv_backlight. Actually, I can change the backlight by echo the value to the acpi_video0/brightness, with “su”. Yet the nv_backlight does not show any effect.

I found that, I can use the keyboard key to adjust the brightness before start the Xfce4. Once the Xfce4 started (with Power Manager), the brightness change takes no effect. And the changes of the brightness is affecting the nv_backlight/brightness. So, I concluded that it is actually fixable by fixing the Xfce4 Power Manager.

As a result, I patched the Xfce4 Power Manager by editing the source code, to remove the “nv_backlight” from the priority. Install this patched package, restart the Xfce4, and now, it works!

Follow

Get every new post delivered to your Inbox.

Join 162 other followers