Semantic Mode

Table of Contents

Author Lee Hinman (leehinman@fastmail.com)
Date 2017-02-22 09:08:35

1 Introduction

Semantic is part of CEDET, which stands for "Collection of Emacs Development Environment Tools". There are other tools in CEDET other than semantic, but today that's all we're going to talk about.

CEDET comes with Emacs, which means that Semantic is included in Emacs. However, the stand-alone version of CEDET includes some semantic features not yet bundled with Emacs itself.

1.1 What is Semantic?

Semantic is all of the pieces and parts needed for doing parsed text analysis in Emacs. It includes

  • Lexer
  • Parser and Incremental Parser1
  • Parser-Generator
  • Database used for storing parsed information
  • Idle services and tools

It allows Emacs to parse source code for semantic information, and use that information in a variety of ways.

1.2 Supported languages

Out of the box, it supports:

  • Emacs Lisp
  • C/C++
  • C#
  • Java
  • Python
  • Erlang
  • awk
  • Makefile
  • Scheme
  • HTML
  • Texinfo
  • Javascript
  • dot (graphviz)

1.3 Features that Semantic provides

Since Emacs can see the structure of source code, it can provide features that regular major modes cannot, such as:

  • Completion (hopefully smarter than other completion)
  • Navigation assistance through imenu and senator2
  • Idle summaries of location, symbol, var, etc
  • Template-based code generation3
  • Smart Bookmarking
  • Highlighting bad/good code
  • Charting of semantic pieces of source code
  • Analysis

2 How to install Semantic

Check what version of Semantic you have bundled with Emacs by doing M-x cedet-version, you should see something like this table:

CEDET Version:  2.0
                  Requested   File      Loaded
  Package         Version     Version   Version
  ------------------------------------------------------------
  cedet:          2.0         ok        ok
  eieio:          1.4         nil       ok
  semantic:       2.2         ok        ok
  srecode:        1.2         ok        ok
  ede:            1.2         2.0       2.0
  cogre:          1.2         ok        ok
  cedet-contrib:  1.2         nil       Not Loaded

You have have to execute (require 'cedet) if cedet-version doesn't immediately work.

Personally, I find it the easiest to run CEDET from source, because I use some of the features that don't come with the bundled version, in order to do that, I clone the repository and set up a early in my init.el configuration

(replace ~/src/elisp/cedet with whatever path you want)

git clone http://git.code.sf.net/p/cedet/git ~/src/elisp/cedet
cd ~/src/elisp/cedet
make

And then early4 in your init.el file:

;; Load a custom version of cedet, if available
(when (file-exists-p "~/src/elisp/cedet/cedet-devel-load.el")
  (load "~/src/elisp/cedet/cedet-devel-load.el"))

Unfortunately there is no MELPA or ELPA package for this, though work is underway to merge CEDET into Emacs itself entirely, so that it can be a native feature instead of half-missing.

Once you've set up CEDET as above, check out cedet-version again and see if it's the same (or different, as long as its installed you should be good to go).

3 How to set up Semantic in your Emacs configuration

Semantic has a lot of different minor modes that can be toggled on and off as needed, they follow the form of

global-semantic-*-mode

These can be used individually, but the best way to configure these is to set the semantic-default-submodes variable to be a list of the modes you want to enable, the default value for this variable is

'(global-semantic-idle-scheduler-mode global-semanticdb-minor-mode)

Which is fine, but you may want to add modes to it

(setq semantic-default-submodes
      '(;; Perform semantic actions during idle time
        global-semantic-idle-scheduler-mode
        ;; Use a database of parsed tags
        global-semanticdb-minor-mode
        ;; Decorate buffers with additional semantic information
        global-semantic-decoration-mode
        ;; Highlight the name of the function you're currently in
        global-semantic-highlight-func-mode
        ;; show the name of the function at the top in a sticky
        global-semantic-stickyfunc-mode
        ;; Generate a summary of the current tag when idle
        global-semantic-idle-summary-mode
        ;; Show a breadcrumb of location during idle time
        global-semantic-idle-breadcrumbs-mode
        ;; Switch to recently changed tags with `semantic-mrub-switch-tags',
        ;; or `C-x B'
        global-semantic-mru-bookmark-mode))

Then it's as simple as adding in your configuration

(add-hook 'emacs-lisp-mode-hook 'semantic-mode)
(add-hook 'python-mode-hook 'semantic-mode)
(add-hook 'java-mode-hook 'semantic-mode)
(add-hook 'c-mode-hook 'semantic-mode)
;; etc etc
(add-hook 'prog-mode-hook 'semantic-mode)

4 How to use Semantic

Most semantic keybindings are behind the prefix

C-c ,
Command What it does Bound to
semantic-mrub-switch-tags show the most recently edited tags C-x B
semantic-ia-show-doc show documentation for the symbol at point  
semantic-ia-show-summary show summary for the symbol at point  
semantic-ia-describe-class describe the prompted class  
semantic-ia-fast-jump jump to the location of a tag  
semantic-symref find references to the symbol at point C-c , G
semantic-complete-jump jump to the location of a tag C-c , J
semantic-complete-jump-local jump to the location of a local tag C-c , j
semantic-complete-analyze-inline completion based on semantic information C-c , SPC
semantic-analyze-possible-completions completion possibilities C-c , l
semantic-force-refresh force semantic to reparse buffers =C-c , ,=

To see what sort of information semantic can parse from a buffer, try M-x bovinate.

5 Demo(s)

5.1 Java (my use)

public class Person {
  private int favoriteNumber;
  private String name;

  Person(String name, int favoriteNumber) {
    this.favoriteNumber = favoriteNumber;
    this.name = name;
  }

  public String getName() {
    return this.name;
  }

  public int getFavoriteNumber() {
    return this.favoriteNumber;
  }

  public void sayHi() {
    Person p = new Person("Lee", 42);
    System.out.println("Hi my name is " + this.name + " and my favorite number is " + this.favoriteNumber);
  }
}

5.2 Emacs Lisp

(defun my-function (x)
  "Returns x + 1"
  (+ 1 x))

5.3 Python

5.4 C/C++

Let's look at some Emacs source!

6 Other Resources

Here are some other links that might help when playing with Semantic/CEDET

Footnotes:

1
If you are familiar with Bison, Semantic includes a reimplemented version of Bison called "Wisent"
2
Senator is another feature of CEDET and is a specialized navigator
4
CEDET needs to be loaded from your checked out version before it's loaded by a different package, which is why this needs to go near the top of your init.el file

Author: Lee Hinman

Created: 2017-02-22 Wed 09:08