xahlee / xah-fly-keys

the most efficient keybinding for emacs
http://xahlee.info/emacs/misc/xah-fly-keys.html
469 stars 80 forks source link

xah-extend-selection could be more powerful #15

Open spiderbit opened 7 years ago

spiderbit commented 7 years ago

So I just for funs try to find a useful setup for python programming under emacs. The problem I describe should be not python-specific cause I guess lets say ruby has similar problems.

The startpoint I wanted to do, is to evaluate statemens/defuns.

the stardard pythen-shell-send-defun is so bad that it will not even execute something simple as: print ("hello world")

while the elisp version of that of course would evaluate: (print "hello world")

So I played around with the eval-in-repl package and with elpy.

Both solve this problem, elpy has a elpy-send-current-statement which basicly linebased calls a statement.

But if you use other statements/scopes with it it will not work:

if True:
    print ("hello")

while in elisp that of course works: (if ((t)((print "hello"))

So you might think, well thats a bug of this modes then, which might be true, or its because this are not fully functional programming languages?

But there is one way python-mode excutes all this examples, if I use the python specific eval-region function, when I select the scopes I am interested in.

So with eval-region I can have treebased or nodebased excution of branches of code. but to manually select the right amount of code, is slow and not very confortable, if xah-extend-selection or a similar mode specific method could expand selection tree based, you could execute some parts of code.

This is not a clear bug-report more a discussion startpoint, and maybe a feature-request.

I am just not shure if emacs / elisp screwed me that I cant write "normal" c-style code anymore at all because I loose all the important tools I use, or if thats at least to a degree fixable :)

I mean clearly a non-pure functional language can not always be executed in a tree based manner but in some cases it works.

Well I guess because you have no "let" construct in python and I guess not in ruby too (that does the same), you often would need to mark the right amount of code manually anyway?

Of course things like hy or clojure would be a option. So I does not make to much sense, what I ask for?

xahlee commented 7 years ago

it's possible to smart select the proper region of python code, for example, single statement, or if statement in multiple lines.

if you really want that, magnars's expand-region.el package can do. You can bind it key 8 to replace xah-extend-selection.

Note that package is extensible, and is contributed by many people for diff languages. That is, the behavior is language dependent, and each has a dedicated lisp file.

i used that package for a year and gave up, because sometimes it can be very slow. I recall, it's in python that made me gave up the package.

the advantage of xah-extend-selection is that it's simple, fast, and universal. But it cannot deal with python code.

xah-extend-selection is also can use a lot improvements i'm working on, such as properly expand by code semantic unit. (currently, it properly expand only to outer parens/brackets, if the cursor began on a bracket)

but i don't think xah-extend-selection will one day cover python syntax. No in the near future. Because it'd require lots special code similar to how expand-region.el needs to be, namely, different files, each elisp file covers one specific language.

spiderbit commented 7 years ago

So I informed myself the last 2 days a bit about programming languages and the details in paradigms, I have studied computer science but it was not informatic, so I guess either I missed the details about that or they did not teach us that.

On the other hand I did not learn to program in my university too, so maybe I should not except them to teach that?

Whatever, I looked at much half backed tries to use python in a functional way using mostly lambda, and function, which can shurly help here and there but are no real answer.

Also its more about the language and not about the toolset.

Here I found something that kind of works for me, and could even work for that specific problem.

You @xahlee mentioned expand-region.el, which is a python-tool and is slow if i understand you right?

I found a maybe better alternative, there are 2 python-modes, the included and another mode with the same name that is as example in melpa, its not just a different version its a complete different package. its alive (changes 2017), I think its the official emacs package from python, if that makes sense.

you just can install it activate python-mode on a buffer, in the indicator bar, you see it as "Py" instead of the normal "Python".

it has functions like: py-execute-block py-execute-statement py-mark-block py-mark-statement py-up-block

The problem I need to figure out would be some wrapper that checks if the current thing/line is a expression before I know if the shoortcut I use as example xah-extend-region, would use:

  1. py-mark-expression or
  2. py-mark-block or
  3. py-up-block + py-mark-block.

if I get there a logic done to determine which to use, it would be basicly a context-aware expand-region.

for py-execute-block I would need a similar logic, but only with the question, is it a statement or a block and then choose between:

  1. py-execute-statement
  2. py-execute-block

A step between would maybe be to ignore statements at all, and only handle blocks and use a second shortcut for statement commands.

But its much much closer to what I want as toolset to work with sourcecode, and what I am used to, with elisp (eval-defun / xah-extend-region).

What do you think?

spiderbit commented 7 years ago

I wrote some proof-of-concept code. I have to call py-statement manuelly for whatever reasons (maybe a bug) to get first the outer print statement selected ( print ("3") ), but after that it expand through the blocks.

(defun py-expand (start end)
  (interactive "r")
  (if (and (equal start (point)) (py-in-statement-p))
      (progn
    (print "call py-statement manually here")
    (py-statement))
    (progn
      (goto-char (- start 1))
      (py-mark-block))))
def test():
    if True:
        print ("1")
        if True:
            print ("2")
            if True
                print("3")

the code is not really good :) but it works. there is shurly a much better way to do that, should ask that that project, but I am to lazy today to create for that a account on Gitlab.

Any thoughts on that, I guess it makes not sense to include it into your package cause first you dont use python? and it depends on another package that comes not with emacs right?

xahlee commented 7 years ago

hi spiderbit,

sometimes i have difficulty understand what you mean. You write a lot, often many topics into one, and often i don't understand exactly what you mean.

for example:

So I informed myself the last 2 days a bit about programming languages and the details in paradigms, I have studied computer science but it was not informatic, so I guess either I missed the details about that or they did not teach us that.

what Do you mean “was not informatic”?

you wrote:

On the other hand I did not learn to program in my university too, so maybe I should not except them to teach that?

so, i don't understand.

1 you did not learn any computer science at university? 2 you did not learn any programing at university? 3 but you have learned some programing yourself?

and similarly, i often don't understand many sentences. (we have a lot discussions before, for example, when we discussed linux keybinding remap... and i often don't understand many of your sentences, or whole paragraph).

you wrote:

You @xahlee mentioned expand-region.el, which is a python-tool and is slow if i understand you right?

it's not “a python tool”. It is a emacs package, and that package's purpose is to extend selection by semantic units, according to what's current language. The package is ten or more files. Each file is dedicated to one language.


now to the topic:

if you really want a extend selection command for python, i recommend just use magnars's expand-region.el. That's the most simple solution, and works well.

now, about the python mode you mentioned, if that works, that's great.

I do code python. Not much. I use just the basic python mode that comes with emacs. I know there's other python modes, and other packages that includes lots features such as interactive evalutation and REPL. I have not used them.

About making xah-extend-selection to be python aware... though, not a priority at the moment. I need to make xah-extend-selection work with generally with any language for now. That is, behavior on selecting string and bracketed text.

spiderbit commented 7 years ago

Sorry, I thought "Informatic" is a general term, used in other countries, Informatic is here in germany a specific degree program of universities. its basicly lots of math and indirectly also algorythms and programming.

I on the other hand had a more general degree program that we call "ingenieure for softwaretechnik". its a less traditional study program, with different focus what to learn.

Also I studied in a university of applied sciences not in a normal traditional university, where the focus is also more on learning as example more concrete programming instead of only abstract concepts and math.

what I meant with, that I did not learn to program in the university, was that I did learn coding before I went to that university, I even had for a while a payed coding job (Web development) before I went to that university.

In the school I went before 2 years we learned a bit C and privately I learned java, because back then 15-20 years ago I thought java is a great language :)

To the "expand-region.el" comment, I did then missunderstand you apperently:

i used that package for a year and gave up, because sometimes it can be very slow. I recall, it's in python that made me gave up the package.

My english isnt that bad right? You said you think its written in python?

xahlee commented 7 years ago

Now i understand what you mean about informatic. In usa, we never call it that. We call Computer Science degree, or Info Technology degree (IT degree). No worry about English. Btw, i also never formally learned programing. Never had any degree.

about expand-region.el, no it's not written in python. It's written in emacs elisp, it's emacs package. (did i misunderstand you?)

if you haven't tried it, i recommend giving it a shot: https://github.com/magnars/expand-region.el because it seems it's exactly what you want. It is a very popular package.

spiderbit commented 7 years ago

ok, I just installed it and yes it does what I wanted at least in relation to (xah-)expand-region.

I just wanna mention that the primary thing I wanted or at least wanted to do, is to execute "nodes" or branches of code.

Using extend-region and then execute-region was more a workaround to that. But its very useful for other aspects of course if you want to copy/paste a block to a new function as example.

So this other python-mode in melpa is still usefull, cause it has a py-execute-block and py-execute-region function, and the official package only has python-shell-send-region which aperently does not execute that code, and no python-shell-send-block?

So besides expanding text tool, this python-mode is still very usefull. But yes for the expanding part expand-region seems to be the better solution.

So in theory it could be usefull to bind the eval specific "SPC w " to py-execute- in python-mode.

spiderbit commented 7 years ago

So I played a bit around with the idea I described, for the eval/execute command it seems to work okish:

(define-key xah-danger-keymap (kbd "e")
  (lambda () (interactive)
    (if (equal major-mode 'python-mode)
    (py-execute-block)
      (eval-defun nil))))

but I have problems to define a mode-specific extend-selection:

(defun spiderbit-extend ()
  (define-key xah-fly-key-map (kbd "8")
    (lambda (arg) (interactive "p")
      (if (equal 'major-mode 'python-mode)
      (er/expand-region arg)
    (xah-extend-selection)))))

(add-hook 'xah-fly-command-mode-activate-hook 'spiderbit-extend)

any tipps? I think it has to do with the interactive expression, you seem to define that very strange in your function that is no char but some function you use as parameter.