Insert comment chars "//" at leftmost position on each line - emacs

1 thing about comment-region I want to change or write a custom function.
Comment-region inserts the "//" at the first non-white-space position, not the leftmost column.
I want the "//" to be inserted at column 0 of each line aka the leftmost position. How?
Update: I found this function seems to be the culprit. Can this be modified to insert at column 0 instead of at first non-white-space column?
(defun my-comment-current-line ()
(interactive)
(beginning-of-line 1)
(insert "//")
)
Thanks, Mike

You want to customize comment-style. E.g.
(setq comment-style 'plain)

Got it
(defun my-comment-current-line ()
(interactive)
(move-beginning-of-line 1)
(insert "//")
)

Related

Emacs24 and python-mode: indention in docstrings

I have the following code/text:
def f():
"""
Return nothing.
.. NOTE::
First note line
second note line
In Emacs23 (23.4.1) I was able to press TAB in the last line ("second note line"; nomatter how this line was indented) and it was aligned correctly like this:
def f():
"""
Return nothing.
.. NOTE::
First note line
second note line
I.e., it uses the previous line and indents the following line in the same way.
Now in Emacs24 (24.3.1) this does not work anymore and it is aligned like this:
def f():
"""
Return nothing.
.. NOTE::
First note line
second note line
I.e. it aligns the multi-line string block, but does not depend on the previous line.
It affects only docstrings; code is indented as I want. I am using python-mode. How can I change this, so that pressing TAB aligns the block correctly?
Python mode has changed quite a bit between Emacs 23 and 24. There is no configuration that would allow you to do what you want.
But, Emacs is quite flexible and you can advise the (python-indent-context) function to make it return a different result that will lead to the behavior you want. The function (python-indent-context) returns a character at which the indentation is measured and used for indenting the current line. By default, when inside a string, it returns the point where the beginning of the string resides. Thus, your line will be indented to the indentation of the start of the string. We can easily modify it to return a point in the previous non-empty line instead, for instance like this:
(defun python-fake-indent-context (orig-fun &rest args)
(let ((res (apply orig-fun args))) ; Get the original result
(pcase res
(`(:inside-string . ,start) ; When inside a string
`(:inside-string . ,(save-excursion ; Find a point in previous non-empty line
(beginning-of-line)
(backward-sexp)
(point))))
(_ res)))) ; Otherwise, return the result as is
;; Add the advice
(advice-add 'python-indent-context :around #'python-fake-indent-context)
The same effect can be achieved using the old defadvice for older Emacs:
(defadvice python-indent-context (after python-fake-indent-context)
(pcase ad-return-value
(`(:inside-string . ,start) ; When inside a string
(setq ad-return-value ; Set return value
`(:inside-string . ,(save-excursion ; Find a point in previous non-empty line
(beginning-of-line)
(backward-sexp)
(point)))))))
(ad-activate 'python-indent-context)
What about editing the section de-stringified in a separate buffer? That would allow python-mode with all its facilities.
Here a first draft - original string will be stored in kill-ring:
(defun temp-edit-docstring ()
"Edit docstring in python-mode. "
(interactive "*")
(let ((orig (point))
(pps (parse-partial-sexp (point-min) (point))))
(when (nth 3 pps)
(let* (;; relative position in string
(relpos (- orig (+ 2 (nth 8 pps))))
(beg (progn (goto-char (nth 8 pps))
(skip-chars-forward (char-to-string (char-after)))(push-mark)(point)))
(end (progn (goto-char (nth 8 pps))
(forward-sexp)
(skip-chars-backward (char-to-string (char-before)))
(point)))
(docstring (buffer-substring beg end)))
(kill-region beg end)
(set-buffer (get-buffer-create "Edit docstring"))
(erase-buffer)
(switch-to-buffer (current-buffer))
(insert docstring)
(python-mode)
(goto-char relpos)))))
When ready, copy the contents back into original buffer.
Which remains to be implemented still.

How to automatically align comments in different pieces of code?

I have to do a very specific task to re-do over and over again and would like to have it put permanently in my .emacs file. But I am not versed enough in emacs-lisp to manage it:
Keystroke-1, say [F8]
remember the current cursors' column position in, say, xtab
Keystroke-2, say [F9] while cursor is in some other line:
find leftmost string // in current line, if none is there, beep and stop
insert as many spaces so the // gets to previously remembered column xtab, or do nothing if cursor is already beyond xtab
search-forward for next // and place the cursor on it
I managed to assign it to a temporary keyboard macro, but have to re-record it for every changing xtab value.
The ultimate goal is that I want to align the comments in different pieces of code easily, from
int main() { // the enty function
int x = 100; // my new variable
for(int i=1; i<2012; ++i) { // loop a lot
x -= i;
}
} // end of all things
to
int main() { // the entry function
int x = 100; // my new variable
for(int i=1; i<2012; ++i) { // loop a lot
x -= i;
}
} // end of all things
Any idea how I can automate this? What do I have to put in my .emacs-file to archive this -- or similar?
As tungd said, align-regexp is good for this sort of thing.
(defun my-align-comments (beginning end)
"Align instances of // within marked region."
(interactive "*r")
(let (indent-tabs-mode align-to-tab-stop)
(align-regexp beginning end "\\(\\s-*\\)//")))
Which is like the interactive call:
M-x align-regexp RET // RET
Or for a more language-agnostic version:
(defun my-align-comments (beginning end)
"Align comments within marked region."
(interactive "*r")
(let (indent-tabs-mode align-to-tab-stop)
(align-regexp beginning end (concat "\\(\\s-*\\)"
(regexp-quote comment-start)))))
Not exactly an answer to your question, but to achieve the desired goal you can just mark the region and use align-regexp.
Here's the code:
(defvar c-current-comment-col 30)
(defun c-set-comment-col ()
(interactive)
(setq c-current-comment-col (current-column)))
(defun c-comment-to-col ()
(interactive)
(beginning-of-line)
(when (re-search-forward "//" (line-end-position) t)
(backward-char 2)
(let ((delta (- c-current-comment-col
(current-column))))
(if (plusp delta)
(insert (make-string delta ? ))
(if (looking-back
(format "\\( \\{%d\\}\\)" (- delta)))
(delete-region
(match-beginning 1)
(match-end 1))
(message
"I'm sorry Dave, I afraid can't do that.")))))
(next-line 1))
(global-set-key [C-f6] 'c-set-comment-col)
(global-set-key [f6] 'c-comment-to-col)
I've added a next-line call to the end. Now you can do
C-f6 f3 f6 M-0 f4 to align until end of buffer.
M-x align is very powerful and will automatically handle the particular example given.
However, it will also align variable declarations, which may be more than you want. In that case, you would have to customize align-region-separate or use the align-regexp answer.

Move point to next tab-stop in Emacs

I am trying to create a major mode in Emacs. In this mode the tab key should work as follows:
I define a number, e.g. (setq my-tab-stop 10)
When I hit the tab key the point moves to next column that is divisible by my-tab-stop, i.e.
If current-column is equal to 0,1,2,..,9, the point should move to column 10,
If current-column is equal to 10,11,12,..,19, the point should move to column 20, and so on..
(Note: no spaces or tabs should be inserted (like in tab-to-tab-stop), only the point moves, however, if the point moves beyond the length of the current line, spaces should be inserted to make line longer)
How can this be done?
Here's the code:
(defvar tabtab-val 10)
(defun tabtab/forward-char (n)
(let ((space (- (line-end-position) (point))))
(if (> space tabtab-val)
(forward-char n)
(move-end-of-line 1)
(insert (make-string (- n space) ? )))))
(defun tabtab ()
(interactive)
(let ((shift (mod (current-column) tabtab-val)))
(tabtab/forward-char (- tabtab-val shift))))
Just bind a key to move-to-tab-stop.
You can trivially configure the tab stop list for fixed intervals of N columns with:
(setq tab-stop-list (number-sequence N MAX N))

Duplicate lines in region "in-place"

I am trying to code an elisp function which takes all (non-empty) lines in the current region and duplicates these lines in-place. I'll give you an example:
This input:
Line1
Line2
Line3
Becomes
Line1
Line1
Line2
Line2
Line3
Line3
If there were empty lines, they would remain in place and should not be duplicated. If have coded the following function:
(defun duplicate-lines-in-region (beg end)
"Duplicates the lines in the current region \"in-place\"."
(interactive "r")
(if (use-region-p)
(let* ((text (buffer-substring-no-properties (region-beginning) (region-end)))
(lines (split-string text "\n" t))
(num-lines (length lines))
(current-line 0)
(end-pos 0))
(save-excursion
(goto-char (region-beginning))
(while (< current-line num-lines)
(end-of-line)
(insert "\n")
(insert (nth current-line lines))
(next-line)
(setq current-line (+ current-line 1))
(setq end-pos (point))))
(goto-char end-pos))
(error "No active region!")))
However, this function has some (at least two) bugs:
Empty lines are not ignored but rather completely destroy the output (lines are inserted in the wrong places).
The first line that is inserted is always inserted with the wrong indentation (at column zero), all other lines are inserted at the right indentation.
I'm kinda stuck with advancing the function to a more useful state. Also, I highly doubt that my approach is particularly efficient/well-written... maybe some elisp-guru knows a more straightforward approach that can be used to work on each line in a region individually...
This might be cheating, but you could just use a regex replace to match non-blank lines and replace them with the captured line and a duplicate. Use M-x replace-regexp with a region highlighted, and the following arguments:
Replace regexp: \(.+\)$
With: \&^J\&
Note, in the above, ^J represents a newline/quoted enter key, C-q C-j.
To translate this into elisp, you just need to make sure to escape the backslashes and parentheses:
(defun duplicate-lines-in-region (beg end)
(interactive "*r")
(replace-regexp "\\(.+\\)$" "\\&\n\\&" nil beg end))

print only text discarding text properties

I have the following function to print the line where point is to the *scratch* buffer,
(defun print-line ()
(print (thing-at-point 'line) (get-buffer "*scratch*")))
but it prints even the fontified info like this
#(" OFFICE
" 0 2 (fontified t org ...
How to discard the printing of the fontified info.
To expand on Daimrod's mention of buffer-substring-no-properties...
M-x apropos RET no-properties RET
buffer-substring-no-properties
Function: Return the characters of part of the buffer, without the
text properties.
field-string-no-properties
Function: Return the contents of the field around POS, without text
properties.
insert-buffer-substring-no-properties
Function: Insert before point a substring of BUFFER, without text
properties.
match-string-no-properties
Function: Return string of text matched by last search, without text
properties.
minibuffer-contents-no-properties
Function: Return the user input in a minibuffer as a string, without
text-properties.
substring-no-properties
Function: Return a substring of STRING, without text properties.
You can read about text properties in the manual:
M-: (info "(elisp) Text Properties") RET
I needed something similar for eredis when manipulating strings from an org-table. You can use `set-text-properties' to get rid of them when displaying the string.
(defun strip-text-properties(txt)
(set-text-properties 0 (length txt) nil txt)
txt)
(defun print-line ()
(print (strip-text-properties
(thing-at-point 'line))
(get-buffer "*scratch*")))
I've tried some things but it's weird, I don't really understand how text properties work.
For example:
(type-of (thing-at-point 'line)) => string
As you've said if one tries to print it, the properties are printed as well, but if one tries to insert it:
(insert (format "%s" (thing-at-point 'line)))
Only the string is printed, not the properties.
So it seems to me that those properties are just bound to the string but you can manipulate the string as usual:
(lenght (thing-at-point 'line))
(substring (thing-at-point 'line) 0 2)
However, if all you want is the line, and the line only you can use buffer-substring-no-properties:
(defun print-line ()
(print (buffer-substring-no-properties (point-at-bol) (point-at-eol))))