tag:blogger.com,1999:blog-67228379838023693062024-03-13T23:33:07.536-07:00emacs dumpUnknownnoreply@blogger.comBlogger23125tag:blogger.com,1999:blog-6722837983802369306.post-57379944774211139512021-12-31T10:02:00.000-08:002021-12-31T10:02:16.990-08:00See what takes time in kernel compilation<p>Makefile projects can be profiled and debugged with the <a href="https://github.com/rocky/remake">remake project</a>. You need a recent version of remake that supports --profile=json (see --help).</p><p>This works with parallel builds as well (I've use -j8 here but use whatever you have).</p><ul><li>"name" is the makefile target</li><li>"len" is the duration in seconds</li></ul><p><br /></p>
<pre>$ cd linux-git<br />$ mkdir -p json && remake --profile=json --profile-directory=$PWD/json -j8<br />$ cd json<br /> </pre><pre># Look at items sorted by total time (time taken by all dependencies + the recipe length)<br />$ jq -s '[.[] |.targets[]|select(.recipe!=null)|{ name: .name, len: (.end-.start) }]|sort_by(-.len)' *.json<br />[<br /> {<br /> "name": "bzImage",<br /> "len": 77.26787257194519<br /> },<br /> {<br /> "name": "vmlinux",<br /> "len": 76.33200693130493<br /> },<br /> {<br /> "name": "arch/x86/kernel/vmlinux.lds",<br /> "len": 75.16884279251099<br /> },<br /> {<br /> "name": "drivers",<br /> "len": 75.013343334198<br /> },<br /> {<br /> "name": "arch/x86/lib/lib.a",<br /> "len": 75.01327657699585<br /> },<br />....</pre><pre><br /></pre><pre><br /></pre><pre># Or look at item sorted by recipe time only (without the dependencies)<br />$ jq -s '[.[] |.targets[]|select(.recipe!=null)|{ name: .name, len: (.end-.recipe) }]|sort_by(-.len)' *json<br />[<br /> {<br /> "name": "drivers",<br /> "len": 47.737035512924194<br /> },<br /> {<br /> "name": "fs",<br /> "len": 45.02375769615173<br /> },<br /> {<br /> "name": "net",<br /> "len": 40.28609848022461<br /> },<br /> {<br /> "name": "net/ipv4",<br /> "len": 31.197179794311523<br /> },<br />...</pre><pre><br /></pre><pre><br /></pre><pre><br /></pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-37917495194826750432019-10-09T07:42:00.000-07:002019-10-09T07:43:13.925-07:00AdressSanitizer link error and autoconf configure scriptIf you get linking errors like the following when trying to use AddressSanitizer in an autoconf project:
<br />
<pre>spnego.c:(.text+0x3c): undefined reference to `__asan_option_detect_stack_use_after_return'
/bin/ld: spnego.c:(.text+0x49): undefined reference to `__asan_stack_malloc_1'
/bin/ld: spnego.c:(.text+0xfd): undefined reference to `__asan_report_load16'
/bin/ld: spnego.c:(.text+0x180): undefined reference to `__asan_report_load8'
/bin/ld: spnego.c:(.text+0x1ad): undefined reference to `__asan_report_load8'
/bin/ld: spnego.c:(.text+0x1ff): undefined reference to `__asan_report_load8'
/bin/ld: spnego.c:(.text+0x22e): undefined reference to `__asan_report_load8'</pre>
<br />
<br />
It's because the configure guesses something wrong. You can work around it by providing the answer via an env var like so:<br />
<br />
<pre>CFLAGS='-fsanitize=address' \
LDFLAGS='-fsanitize=address' \
ac_cv_func_malloc_0_nonnull=yes \
./configure</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-80309205238531911512018-05-02T02:40:00.000-07:002018-05-02T02:40:15.572-07:00notmuch mark as spamAdds a keybinding that applies/removes tags to the currently viewed email or --when looking at search results-- the thread under point.
<pre>
(defun mark-spam ()
(interactive)
(let ((tlist '("+spam" "-unread" "-inbox" "-new")))
(if (eq major-mode 'notmuch-show-mode)
(progn
(let ((id (notmuch-show-get-message-id)))
(notmuch-tag id tlist)
(notmuch-show-next-thread)))
(notmuch-search-tag tlist)
(notmuch-search-next-thread))))
(define-key 'notmuch-search-mode-map (kbd "S") 'mark-spam)
(define-key 'notmuch-show-mode-map (kbd "S") 'mark-spam)
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-50585433671524658752017-02-17T11:53:00.002-08:002018-01-24T04:58:32.741-08:00_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build<pre>_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build</pre>
<br />
<br />
If you are pulling your hair and wondering why your kernel does not have a <code>/sys/kernel/debug/<b>dynamic_debug</b></code> directory despite having <code>CONFIG_DYNAMIC_DEBUG</code> enabled and <code>debugfs</code> mounted, the issue could be that you built the kernel using GOLD linker. You can simply switch through the LD Makefile variable (<code>make LD=ld.bfd</code>)Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-63549231821172553722017-01-16T08:23:00.001-08:002017-01-16T08:23:11.554-08:00Extracting and applying a clean git patchset from an email thread with notmuchI just wrote a quick python script to filter the actual patches from a email thread send with git send-email (those "[PATCH 1/15] xyz" threads). The script assumes you use notmuch. Give it a search expression that returns a list of messages that includes all the patches like the thread-id (<code>C-u c i</code> while looking at the thread in emacs).<br />
<br />
You can get it on <a href="https://github.com/aaptel/notmuch-extract-patch">github</a>. There is a small elisp snippet in the README to run the script and apply the patchset from emacs.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-79879158631013061352017-01-13T08:42:00.000-08:002017-01-13T08:42:10.339-08:00Copy current buffer absolute file path to the OS clipboard<pre>
(defun copy-full-path ()
(interactive)
(let ((path (buffer-file-name)))
(when path
(setq path (expand-file-name path))
(funcall interprogram-cut-function path)
(message "copied %s in clipboard" path))))
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-79724387236931554532017-01-13T08:35:00.001-08:002017-01-13T08:35:41.224-08:00Quick-and-dirty email template for notmuch<pre>
(defun prepare-report ()
(interactive)
(notmuch-mua-new-mail)
(insert "foo@example.com")
(search-forward "Subject: ")
(insert "work report week " (format-time-string "%W"))
(search-forward "\n\n")
(backward-char)
(insert "my super email content\n"))
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-73428672733497824472017-01-13T08:31:00.001-08:002017-01-13T08:31:53.080-08:00Jump to code from Coverity report emails (notmuch)<p>If you use notmuch as your email client and receive Coverity reports emails, here's a quick function that compiles the reports to a single buffer (newest first), applies some color on the errors, and enables the compilation minor mode so you can use Emacs regular "jump to next error" key.
</p>
<p>Adapt the default-directory to your project source.</p>
<pre>(defun samba-coverity ()
(interactive)
(let ((b (get-buffer-create "*coverity*")))
(with-current-buffer b
(erase-buffer)
(setq default-directory (expand-file-name "~/prog/samba-git"))
(insert
(shell-command-to-string
(concat
"for i in $(notmuch search --output=messages"
" 'from:scan-admin@coverity.com'); do notmuch show $i; done"
" | perl -pE 's,^/(\\S+): (\\d+) in,cov:$1:$2: in,'")))
(goto-char (point-min))
(while (search-forward-regexp (rx bol ">>>") nil t)
(let ((beg (save-excursion (beginning-of-line) (point)))
(end (save-excursion (end-of-line) (point))))
(put-text-property beg end 'face 'error)))
(goto-char (point-min))
(compilation-minor-mode))
(switch-to-buffer b)))</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-59695160233932176802016-04-08T05:42:00.001-07:002016-04-08T05:43:27.211-07:00Insert new rpm-style changelog entry<pre>(defun new-changelog-entry ()
(interactive)
(let ((line-len 67)
(date (substring (shell-command-to-string "LC_ALL=C date -u") 0 -1))
;; (email user-mail-address) probably wrong
(email (concat user-real-login-name "@suse.com"))
(final-pos))
(goto-char (point-min))
(insert (make-string line-len ?-) "\n"
date " - " email "\n\n"
" - ")
(setq final-pos (point))
(insert "\n\n")
(goto-char final-pos)))
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-24703502456059343252016-03-22T08:44:00.001-07:002016-04-28T04:55:47.804-07:00Analyzing Samba with PVS-Studio on Linux<p>
If you have followed the last developement in C/C++ static analysis
tools you must have heard of <a href="http://www.viva64.com/en/pvs-studio/">PVS-Studio</a>. I heard of them through the
articles they publish on their site where they analyze open source
projects. They have analyzed quite big projects including the Linux
kernel, Qt, Unreal, … and they have always managed to find crazy
bugs that have been siting there for some time, undetected. Typos, bad
copy-paste, undefined behaviours, non-sense code, syntax errors that
miraculously still compile… As John Carmack said:
</p>
<blockquote>
<p>
Everything that is syntactically legal that the compiler will accept
will eventually wind up in your codebase.
</p>
</blockquote>
<p>
Unfortunately, the tool is advertized as Windows-only. The program
comes in the form of a Visual Studio plugin or a separate independent
program if you don't have the former. I first used it back in
2014 on a relatively large C++ codebase used internally in the
computer graphics department of my university in Lyon (<a href="https://liris.cnrs.fr/presentation-en/laboratory-presentation">LIRIS</a>). We were
using Visual Studio (which I normally rarely use) so I thought I should
give it a try. I was really pleased with the results and kept checking
the PVS-Studio website for more articles.
</p>
<p>
Two years and several PVS-Studio articles later I started working on
<a href="http://samba.org">Samba</a>. The whole project is about 2 millions lines of C code and I
thought it would be a good candidate for PVS-Studio. A static analysis
tool shouldn't have too much platform-specific code so I started
thinking about it. The analyzer works on preprocessed code so it needs
to run the preprocessor on your sources and for that it needs all your
preprocessor flags, macros and includes path. Gathering this
automatically can be painful. For this step I wrote a strace-based
script that "spies" your build tool for compiler calls, that way it
should be build-tool agnostic. You can find the latest version of <a href="https://github.com/aaptel/pvs-tool">this
tool on github</a>.
</p>
<p>
I sent the script to the PVS-Studio guys and after some back and
forth, I was given an experimental Linux build of PVS-Studio (thanks
again!). The script now covers all the analyzing process from
gathering compiler flags, to analyzing, displaying and filtering
the results.
</p>
<p>Here's how you use it.</p>
<p>In order to not have to point to the license and binary at every use
you can set up env variables.</p>
<pre>
$ export PVS_LICENSE=~/prog/pvs/PVS-Studio.lic
$ export PVS_BIN=~/prog/pvs/PVS-Studio
</pre>
<p>
Go to your project directory and generate a config file for your
C++11 project.
</p>
<pre>
$ pvs-tool genconf -l C++11 pvs.cfg
</pre>
<p>
If you need to configure the build before building, do it. Then trace
the actual build (your build command should go after the <code>--</code>).
</p>
<pre>
$ pvs-tool trace -- make -j8
</pre>
<p>
This will output a "strace_out" file which have all the information we
need. The analyze step will process that file to extract all
compilation units and preprocessor flags, and run PVS-Studio on it.
</p>
<pre>
$ pvs-tool analyze pvs.cfg
pvs-tool: deleting existing log pvs.log...
001/061 [ 0%] analyzing /hom../rtags/src/ClangIndexer.cpp...
002/061 [ 1%] analyzing /hom../rtags/src/CompilerManager.cpp...
003/061 [ 3%] analyzing /hom../rtags/src/CompletionThread.cpp...
004/061 [ 4%] analyzing /hom../rtags/src/DependenciesJob.cpp...
<...>
061/061 [98%] analyzing /hom../rtags/src/rp.cpp...
pvs-tool: analysis finished
pvs-tool: cleaning output...
pvs-tool: done (2M -> 0M)
</pre>
<p>
The cleaning part removes duplicated lines and will drastically reduce
the file size of big results.
</p>
<p>
You can now view the results, grouped by files
</p>
<pre>
$ pvs-tool view pvs.log
</pre>
<p>
The output is similar to gcc/make so it works as-is in e.g. the Emacs
editor and I can use my usual builtin goto-error functions. You can
disable diagnostics e.g.
</p>
<pre>
$ pvs-tool view -d V2006,V2008 pvs.log
</pre>
<p>
By default it only shows level 1 errors but you can change it with -l.
</p>
<p>
You can look at the -h help messsage for more.
</p>
<hr/>
<p>
PVS-Studio found <b>many</b> problems in Samba. Most of them were false positives
but this is expected when you use any static analysis tool on large
codebase. The important thing is it also found real bugs. I'm going to
share the most interesting ones along with their fix, in the form of
diffs.
</p>
<pre class="example">
- if (memcmp(u0, _u0, sizeof(u0) != 0)) {
+ if (memcmp(u0, _u0, sizeof(*u0)) != 0) {
printf("USER_MODALS_INFO_0 struct has changed!!!!\n");
return -1;
}
</pre>
<p>
Here, the closing parenthesis was misplaced. The result of the
<code>sizeof</code> comparaison was used as the compared memory size (always 1
byte). Also, we want the size of the type <code>u0</code> points to, not the size
of the pointer.
</p>
<hr />
<pre class="example">
handle_main_input(regedit, key);
update_panels();
doupdate();
- } while (key != 'q' || key == 'Q');
+ } while (key != 'q' && key != 'Q');
</pre>
<p>
Here, we want to exit the loop on any case of the letter 'q'.
</p>
<hr />
<pre class="example">
uid = request->data.auth.uid;
- if (uid < 0) {
+ if (uid == (uid_t)-1) {
DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
return -1;
}
</pre>
<p>
Here we tested the <code>uid_t</code> type for negative values.
</p>
<p>
The sign of the <code>uid_t</code> type is left unspecified by POSIX. It's defined as
an unsigned 32b int on Linux, therefore the <code>< 0</code> check is always
false.
</p>
<p>
For unsigned version of <code>uid_t</code>, in the comparaison <code>uid == -1</code> the
compiler will implicitely cast -1 to unsigned making it a valid test
for both signed and unsigned version of <code>uid_t</code>. I've made the cast
explicit because less magic is better in this case.
</p>
<hr />
<pre class="example">
DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
- pam_error = pam_authenticate(pamh, PAM_SILENT | allow_null_passwords ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
+ pam_error = pam_authenticate(pamh, PAM_SILENT | (allow_null_passwords ? 0 : PAM_DISALLOW_NULL_AUTHTOK));
switch( pam_error ){
case PAM_AUTH_ERR:
DEBUG(2, ("smb_pam_auth: PAM: Authentication Error for user %s\n", user));
</pre>
<p>
Simple operator priority error.
</p>
<hr />
<pre class="example">
gensec_init();
dump_args();
- if (check_arg_numeric("ibs") == 0 || check_arg_numeric("ibs") == 0) {
+ if (check_arg_numeric("ibs") == 0 || check_arg_numeric("obs") == 0) {
fprintf(stderr, "%s: block sizes must be greater that zero\n",
PROGNAME);
exit(SYNTAX_EXIT_CODE);
</pre>
<p>
Here the test was doing the same thing twice.
</p>
<hr />
<pre class="example">
if (!gss_oid_equal(&name1->gn_type, &name2->gn_type)) {
*name_equal = 0;
} else if (name1->gn_value.length != name2->gn_value.length ||
- memcmp(name1->gn_value.value, name1->gn_value.value,
+ memcmp(name1->gn_value.value, name2->gn_value.value,
name1->gn_value.length)) {
*name_equal = 0;
}
</pre>
<p>
Here <code>memcmp</code> was called with the same pointer, thus comparing the
same region of memory with itself.
</p>
<hr />
<pre class="example">
ioctl_arg.fd = src_fd;
ioctl_arg.transid = 0;
ioctl_arg.flags = (rw == false) ? BTRFS_SUBVOL_RDONLY : 0;
- memset(ioctl_arg.unused, 0, ARRAY_SIZE(ioctl_arg.unused));
+ memset(ioctl_arg.unused, 0, sizeof(ioctl_arg.unused));
len = strlcpy(ioctl_arg.name, dest_subvolume,
ARRAY_SIZE(ioctl_arg.name));
if (len >= ARRAY_SIZE(ioctl_arg.name)) {
</pre>
<p>
Here <code>memset</code> was given the size as a number of elements instead of a byte size.
</p>
<hr />
<pre class="example">
if (n + IDR_BITS < 31 &&
- ((id & ~(~0 << MAX_ID_SHIFT)) >> (n + IDR_BITS))) {
+ ((id & ~(~0U << MAX_ID_SHIFT)) >> (n + IDR_BITS))) {
return NULL;
}
</pre>
<p>
Using negative values on the left-side of a left-shift operation is an
Undefined Behaviour in C.
</p>
<hr />
<pre class="example">
if (cli_api(cli,
param, sizeof(param), 1024, /* Param, length, maxlen */
- data, soffset, sizeof(data), /* data, length, maxlen */
+ data, soffset, data_size, /* data, length, maxlen */
&rparam, &rprcnt, /* return params, length */
&rdata, &rdrcnt)) /* return data, length */
{
</pre>
<p>
Here <code>data</code> used to be a stack allocated array but was changed to a heap
allocated buffer without updating the <code>sizeof</code> use.
</p>
<hr />
<pre class="example">
goto query;
}
- if ((p->auth.auth_type != DCERPC_AUTH_TYPE_NTLMSSP) ||
- (p->auth.auth_type != DCERPC_AUTH_TYPE_KRB5) ||
- (p->auth.auth_type != DCERPC_AUTH_TYPE_SPNEGO)) {
+ if (!((p->auth.auth_type == DCERPC_AUTH_TYPE_NTLMSSP) ||
+ (p->auth.auth_type == DCERPC_AUTH_TYPE_KRB5) ||
+ (p->auth.auth_type == DCERPC_AUTH_TYPE_SPNEGO))) {
return NT_STATUS_ACCESS_DENIED;
}
</pre>
<p>
Prior to this fix, the condition was always true and the function
always returned "access denied".
</p>
<hr />
<pre class="example">
- Py_RETURN_NONE;
talloc_free(frame);
+ Py_RETURN_NONE;
}
</pre>
<p>
<code>Py_RETURN_NONE</code> is a macro that hides a return statement. In this
python binding many functions were returning before freeing heap
allocated memory. This problem was present in dozens of functions.
</p>
<hr />
<pre class="example">
int i;
- for (i=0;ARRAY_SIZE(results);i++) {
+ for (i=0;i<ARRAY_SIZE(results);i++) {
if (results[i].res == res) return results[i].name;
}
return "*";
</pre>
<p>
Here the for condition was always true.
</p>
<hr />
<pre class="example">
int create_unlink_tmp(const char *dir)
{
+ if (!dir) {
+ dir = tmpdir();
+ }
+
size_t len = strlen(dir);
char fname[len+25];
int fd;
mode_t mask;
- if (!dir) {
- dir = tmpdir();
- }
-
</pre>
<p>
Here the <code>dir</code> pointer was used before the null-check.
</p>
<p>
Overall I'm really pleased with PVS-Studio and I would recommend
it. Unfortunately it's not officially available on Linux. Although you
can just contact them if you're interested it seems :)
</p>
Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-6722837983802369306.post-47916160138682702172016-03-17T06:10:00.001-07:002016-03-17T06:12:00.638-07:00Edit files and run stuff on remote hosts (Tramp quick how to)Edit file on remote host (ssh .config aware)
<pre>C-x C-f /<host>:<path></pre>
You can use your .ssh config hosts when replacing <host>. This sets the buffer <code>current-directory</code> to the remote one, and many parts of emacs take advantage of that (M-x shell, compile, ...).
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-56183084026486851552016-03-03T07:25:00.002-08:002016-03-03T07:25:57.219-08:00Guess C indent rules based on the buffer content<p>Guess basic indent rules from the buffer content. You can add this to the c-mode hook, works good enough.</p>
<pre>(defun guess-c-indent-rules ()
(interactive)
(save-excursion
(goto-char (point-min))
(cond
;; check GNU first (1-level indent is 2 space)
((search-forward-regexp (rx bol " " (or "if" "do" "while" "for" "return")) nil t)
(message "GNU style detected, setting it...")
(c-set-style "gnu"))
;; linux style tab indent (samba)
((search-forward-regexp (rx bol (+ "\t") (or "if" "do" "while" "for")) nil t)
(message "indenting with 8-spaces tabs detected, linux style...")
(c-set-style "linux")
(setq indent-tabs-mode t
c-basic-offset 8))
;; 4 space mode
((search-forward-regexp (rx bol (+ " ") (or "if" "do" "while" "for")) nil t)
(message "indenting with 4 spaces...")
(setq indent-tabs-mode nil
c-basic-offset 4))
(t
(message "cannot guess indentation, you're on your own!")))))</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-23328955124872610582015-10-29T08:54:00.000-07:002015-10-29T09:16:23.845-07:00Delete lines matching a regex; Keep lines matching a regexp<code>kill-lines-rx</code> will prompt you for a regex and delete all lines matching it. Use with a prefix argument (<kbd>C-u</kbd>) to highlight and ask before removing.
<pre>
(defun kill-lines-rx (&optional ask)
(interactive "P")
(save-excursion
(goto-char (point-min))
(let ((rx (read-regexp "Rx: ")))
(while (search-forward-regexp rx nil t)
(beginning-of-line)
(set-mark (save-excursion (end-of-line) (point)))
(when (or (not ask) (y-or-n-p "Kill? "))
(delete-region (point) (mark))
(delete-char 1))))))
</pre>
<code>kill-lines-unless-rx</code> will prompt you for a regex and delete all lines <strong>not</strong> matching it. Use with a prefix argument (<kbd>C-u</kbd>) to highlight and ask before keeping.
<pre>
(defun kill-lines-unless-rx (&optional ask)
(interactive "P")
(let (keep)
(save-excursion
(goto-char (point-min))
(let ((rx (read-regexp "Rx: ")))
(while (search-forward-regexp rx nil t)
(beginning-of-line)
(set-mark (save-excursion (end-of-line) (point)))
(when (or (not ask) (y-or-n-p "Keep? "))
(push (buffer-substring (point) (mark)) keep))
(forward-line))))
(erase-buffer)
(dolist (e (nreverse keep))
(insert e "\n"))))
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-88928112964612051702015-09-04T05:18:00.000-07:002015-09-04T05:18:39.676-07:00org-mode live html export preview in the browserUsing the <a href="https://addons.mozilla.org/fr/firefox/addon/mozrepl/">MozRepl</a> Firefox extension along with Emacs <a href="https://github.com/bard/mozrepl/blob/master/chrome/content/moz.el">moz.el</a> package you can export your current org document to html on each buffer change or on each save.
There's a bunch of JS code to make Firefox resuse existing tabs instead of opening new ones. Run <kbd>M-x toggle-live-preview</kbd> or <kbd>M-x toggle-preview-on-save</kbd> depending on what you want.
<pre>
(defvar moz-useful-functions "
function find_tab_with_url(url) {
var bs = gBrowser.browsers
for (var i = 0; i < bs.length; i++) {
try {
if (bs[i].currentURI.spec == url)
return i
} catch (e) {}
}
return -1
}
function select_tab(t) {
if (gBrowser.selectedTab != t)
gBrowser.selectedTab = t
}
function add_or_reload_url (url) {
var i = find_tab_with_url(url)
var t = ''
if (i < 0) {
t = gBrowser.addTab(url)
} else {
gBrowser.browsers[i].reload()
t = gBrowser.tabs[i]
}
select_tab(t)
}
")
(defun preview-buffer-in-firefox ()
(interactive)
(require 'moz)
(moz-send-string moz-useful-functions)
(let ((fn (org-html-export-to-html)))
(moz-send-string (concat "add_or_reload_url(\"file://" (expand-file-name fn) "\");\n"))))
(defun live-preview (&optional beg end len)
(when (or (not (and beg end len)) (and beg end len (/= (1+ (- end beg)) len)))
(message "%s: update!" (format-time-string "%r"))
(preview-buffer-in-firefox)))
(defun toggle-live-preview ()
(interactive)
(if (memq 'live-preview first-change-hook)
(remove-hook 'first-change-hook 'live-preview 'buffer-local)
(add-hook 'first-change-hook 'live-preview nil 'buffer-local)))
(defun toggle-preview-on-save ()
(interactive)
(if (memq 'live-preview after-save-hook)
(remove-hook 'after-save-hook 'live-preview 'buffer-local)
(add-hook 'after-save-hook 'live-preview nil 'buffer-local)))
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-71908604958238717662015-08-17T07:39:00.000-07:002015-08-17T07:39:25.501-07:00Quickly edit your init fileNothing fancy about this, just handy: opens my init file and place cursor at the end.
<pre>
(defun init ()
(interactive)
(find-file "~/.emacs.d/init.el")
(goto-char (point-max)))
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-87990078124328044072015-08-17T07:23:00.001-07:002015-08-17T07:23:28.856-07:00Rename file and bufferI don't know why this is not built-in...
<pre>
(defun rename-file-and-buffer (new-name)
"Renames both current buffer and file it's visiting to NEW-NAME."
(interactive "sNew name: ")
(let ((name (buffer-name))
(filename (buffer-file-name)))
(if (not filename)
(message "Buffer '%s' is not visiting a file!" name)
(if (get-buffer new-name)
(message "A buffer named '%s' already exists!" new-name)
(progn
(rename-file name new-name 1)
(rename-buffer new-name)
(set-visited-file-name new-name)
(set-buffer-modified-p nil))))))
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-69201271648860408222015-08-17T07:22:00.003-07:002015-08-17T07:22:37.827-07:00Open current file as rootDon't think I've written this one myself and I don't remember where it comes from. Oh well.
<pre>
(defun sudo-edit (&optional arg)
"Edit currently visited file as root.
With a prefix ARG prompt for a file to visit.
Will also prompt for a file to visit if current
buffer is not visiting a file."
(interactive "P")
(if (or arg (not buffer-file-name))
(find-file (concat "/sudo:root@localhost:"
(ido-read-file-name "Find file(as root): ")))
(find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name))))
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-45554245574779629452015-08-16T07:57:00.000-07:002015-08-25T10:04:43.011-07:00Number line in region using custom printf-like formatBy default starts at zero, but you can use <kbd>C-u 50 M-x my-number-line</kbd> to make it start at 50...<br/>
The commands asks for a printf format that will be inserted at the start of each line, so you can do right alignment, hex, whatever.<br/>
<br/>
Example region:
<pre>
Pellentesque tristique imperdiet tortor. Cras placerat accumsan
nulla. Donec hendrerit tempor tellus. Nam a sapien. Nam vestibulum
accumsan nisl. Donec at pede. Pellentesque dapibus suscipit
ligula. Nunc porta vulputate tellus. Nunc aliquet, augue nec
adipiscing interdum, lacus tellus malesuada massa, quis varius mi
purus non odio. Nunc rutrum turpis sed pede. Etiam vel tortor sodales
tellus ultricies commodo.
</pre>
Mark all lines, <kbd>M-x my-number-line RET 0x%03x SPC RET</kbd> and BAM, lines are prefixed with hex line numbers:
<pre>
0x000 Pellentesque tristique imperdiet tortor. Cras placerat accumsan
0x001 nulla. Donec hendrerit tempor tellus. Nam a sapien. Nam vestibulum
0x002 accumsan nisl. Donec at pede. Pellentesque dapibus suscipit
0x003 ligula. Nunc porta vulputate tellus. Nunc aliquet, augue nec
0x004 adipiscing interdum, lacus tellus malesuada massa, quis varius mi
0x005 purus non odio. Nunc rutrum turpis sed pede. Etiam vel tortor sodales
0x006 tellus ultricies commodo.
</pre>
<pre>
(defun my-number-line (arg beg end fmt)
(interactive "P\nr\nsformat: ")
(let ((n (if (numberp arg) arg 0)))
(save-excursion
(goto-char beg)
(beginning-of-line)
(while (< (point) end)
(beginning-of-line)
(let ((s (format fmt n)))
(insert s)
(incf end (length s)))
(incf n)
(forward-line)
(beginning-of-line)))))
</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-31119606436967327072015-08-16T07:41:00.002-07:002015-08-16T07:41:39.079-07:00Put readable file encoding and line endings mode in the mode-lineI was never able to decipher the default mode-line information about encoding/line endings so I changed it:<br />
<br />
<pre>
(defvar my-mode-line-coding-format
'(:eval
(let* ((code (symbol-name buffer-file-coding-system))
(eol-type (coding-system-eol-type buffer-file-coding-system))
(eol (if (eq 0 eol-type) "UNIX"
(if (eq 1 eol-type) "DOS"
(if (eq 2 eol-type) "MAC"
"???")))))
(concat code " " eol " "))))
(put 'my-mode-line-coding-format 'risky-local-variable t)
(setq-default mode-line-format (substitute 'my-mode-line-coding-format 'mode-line-mule-info mode-line-format))
</pre>
Now you get "utf-8 UNIX" in place of the cryptic "U*:%" whatever bullshit it was.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-79484286091991388832015-08-16T07:34:00.001-07:002015-08-17T07:43:44.884-07:00Make delete-forward do what I mean<ul>
<li>If you're on a non-space character, delete forward until the next space character.</li>
<li>If you're on a space character, delete forward until the next non-space character</li>
</ul>
<pre>
(defun my-delete-space-forward ()
(interactive)
(let* ((char (buffer-substring-no-properties (point) (1+ (point))))
(notspace-rx (rx (not (any "\t\n "))))
(space-rx (rx (any "\t\n ")))
(rx (if (string-match-p space-rx char) notspace-rx space-rx))
(end-pos (save-excursion
(search-forward-regexp rx nil 'end))))
(delete-region (point) (if end-pos (1- end-pos) (point-max)))))
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-30837113549732655142015-08-16T07:30:00.003-07:002015-08-16T07:30:39.591-07:00Make current file executableSmall snippet to make the script you're editing executable:<br />
<br />
<pre>
(defun chmodx (file)
(interactive
(list (buffer-file-name)))
(cond ((null file)
(error "file is nil"))
((not (stringp file))
(error "file is not a string"))
((not (file-exists-p file))
(error "%s doesn't exists" file)))
(shell-command (concat "chmod +x " (shell-quote-argument file))))
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-15980352330774150582015-08-16T07:27:00.000-07:002015-08-16T07:27:12.035-07:00Generate gtkdoc-like comments in C codeI've worked on a C project where I needed to document C functions a certain way (similar to GtkDoc I think) using comments. I made a C prototype parser that mostly work.<br />
The cursor has to be anywhere before the opening brace {. Given this example from PulseAudio:
<br />
<pre>int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d) {
pa_strbuf *buf = NULL;
int c;
int b;
pa_assert(conf);
pa_assert(argc > 0);
pa_assert(argv);
/* yada yada... */
}
</pre>
You get this, with the cursor placed on the function description (right of the -):
<br />
<pre>/**
* pa_cmdline_parse -
* @conf:
* @argc:
* @argv:
* @d:
*
*
*/
int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d) {
pa_strbuf *buf = NULL;
int c;
int b;
pa_assert(conf);
pa_assert(argc > 0);
pa_assert(argv);
/* yada yada... */
}
</pre>
Pretty cool huh? Here's the shitty C parser and doc generator:
<br />
<pre>(defun my-c-parse-function ()
(interactive)
(require 'cl)
(let ((beg (point))
end
text
fname
args)
(save-excursion
(when (search-forward "{" nil t)
(setq end (point)
text (buffer-substring-no-properties beg end))
(setq text (replace-regexp-in-string (rx (+ space)) " " text))
(setq text (replace-regexp-in-string (rx (+ space)) " " text))
(when (string-match (rx (group (+? (not space))) (* space) "(" (group (* any)) ")") text)
(setq fname (match-string 1 text)
args (match-string 2 text))
(setq args (split-string args (rx (? space) "," (? space)) t))
(setq args (mapcar (lambda (arg)
(setq arg (replace-regexp-in-string (rx bos (+ space)) "" arg))
(setq arg (replace-regexp-in-string (rx (+ space) eos) "" arg))
(setq arg (replace-regexp-in-string (rx
"[" (* (not (any "]"))) "]")
"" arg))
(if (string= arg "void")
arg
(let ((words (split-string arg (rx (any "*" space)) t)))
(nth (1- (length words)) words)))) args))
(message "fname = <%s>" fname)
(dolist (a args)
(message "arg<%s>" a))
(append (list fname) (remove-if (lambda (x) (string= x "void")) args))
)))))
(defun my-c-doc-function ()
(interactive)
(let* ((res (my-c-parse-function))
(fname (car res))
(args (cdr res))
p)
(insert "/**\n * " fname " - ")
(setq p (point))
(insert "\n")
(dolist (a args)
(insert " * @" a ": \n"))
(insert " *\n *\n */")
(goto-char p)))
</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6722837983802369306.post-56988589454188075642015-08-16T07:03:00.002-07:002015-08-16T07:04:12.976-07:00shell-mode: make C-l clear the output and remove duplicate input linesC-l usually calls recenter-top-bottom which I never use... On the other end, I often use C-l in terminals to erase/clean them.<br />
<br />
Also shell-mode writes the input buffer twice by default. Let's fix that.<br />
<pre>
(defun my-shell-mode-hook ()
"Set shell mode stuff"
(setq comint-process-echoes 1)
(local-set-key (kbd "C-l") 'erase-buffer))
(add-hook 'shell-mode-hook 'my-shell-mode-hook)
</pre>Unknownnoreply@blogger.com0