Use global recursive from different functions in vimscript - vim

I want to use multiple globals in different functions in vimscript but I get the following error:
"Cannot do :global recursive"
To my problem: I have a config file with paths to multiple XML-files. I want to use a global for every path in the config file and a global for every tag in each XML-File.
So I have some thing like this:
global search-for-a-file-path call functionX(filepath)
functionX(filepath)
edit filepath
global search-for-tags call functionThatDoesStuff()
functionThatDoesStuff()
Stuff happens here...
Is there a possibility to make this work with globals or do I need to use a different approach?
P.S.: I already saw this Q&A but it did not help me because I use the globals in different functions and the solution only shows how it is done in a "one-liner".

Vimscript does simply not seem to be able to do it, so I came up with the following solution:
while search("the-thing-I-search-for") > 0
call functionThatDoesStuff()
end while
My thanks go to Martin for help on the matter.

Related

Is there a better/more pythonic way to load an arbitrary set of functions from modules in another folder?

I'm just basically asking:
if it's considered OK to use exec() in this context
if there's a better/more pythonic solution
for any input or comments on how my code could be improved
First, some context. I have main.py which basically takes input and checks to see if I've written a command. Let's say I type '/help'. The slash just tells it my input was supposed to be a command, so then it checks if a function called 'help' exists, and if so, that function will be run.
To keep things tidy in main.py, and to allow myself to add more commands easily, I have a 'commands' directory, with individual command files in it, such as help.py. help.py would look like this for example:
def help():
print("You've been helped")
So then of course, I need to import help() from help.py, which was trivial.
As I added more commands, I decided to add an init.py file where I'd keep all the command import lines of code, and then just do 'from init import *' in main.py. At first, each time I added a command, I'd add another line in init.py to import it. But that wasn't as flexible as I wanted, so I thought, there's got to be a way to just loop through all the .py files in my commands directory and import them. I struggled with this for a while but came up with a solution that works.
In the init.py snippet below, I loop through the commands directory (and a couple others, but they're irrelevant to the question), and you'll see I use the dreaded exec() function to actually import the commands.
loaded, failed = '', ''
for directory in command_directories:
command_list = os.listdir(directory)
command_list.sort()
for command_file in command_list:
if command_file.endswith(".py"):
command_name = command_file.split(".")[0]
try:
# Evil exec() hack to use variable-name directories/modules
# Haven't found a more... pythonic... way to do this
exec(f"from {directory}.{command_name} import {command_name}")
loaded = loaded + f" - Loaded: {command_name}\n"
except:
failed = failed + f" - Failed to load: {command_name}\n"
if debug == True:
for init_debug in [loaded, failed]: print(init_debug)
I use exec() because I don't know a better way to make a variable with the name of the function being loaded, so I use {command_name} in my exec string to arbitrarily evaluate the variable name that will store the function I'm importing. And... well, it works. The functions work perfectly when called from main.py, so I believe they are being imported in the correct namespace.
Obviously, exec() can be dangerous, but I'm not taking any user input into it, just file names. Filenames that I only I am creating. This program isn't being distributed, but if it was, then I believe using exec() would be bad since there's potential someone could exploit it.
If I'm wrong about something, I'd love to hear about it and get suggestions for a better implementation. Python has been very easy to pick up for me, but I'm probably missing some of the fundamentals.
I should note, I'm running python 3.10 on replit (until I move this project to another host).

How to print function call timeline?

I would like to print location and function name of each function during a run.
It would help during debug to identify which function is called when multiple functions have the same name in different places.
It is possible but time costly to add by hand message such as:
println!("(function_name) file = {}, line = {}",file!(),line!());
Do you know such a solution? Have you suggestions to identify easily which function is called and who calls it?
The easiest option would probably be to use something like dtrace or ebpf: hook onto the "function entry" probe (not sure what it's called in linux / ebpf land but I'd think it exists) and just print the relevant information. You may want to add stack-based indentation though, and of course because of compiler optimisations you might have functions going missing. And you might get the mangled names which is not great, but de-mangling is a thing.
You might be able to do something similar by running your program in gdb and creating some sort of programmatic breakpoints which print and immediately continue?
Alternatively, a module-level attribute procedural macro could work: if you get a token stream for the entire module, it might be possible to automatically inject logging data into every function header.

Can I alter Python source code while executing?

What I mean by this is:
I have a program. The end user is currently using it. I submit a new piece of source code and expect it to run as if it were always there?
I can't find an answer that specifically answers the point.
I'd like to be able to say, "extend" or add new features (rather than fix something that's already there on the fly) to the program without requiring a termination of the program (eg. Restart or exit).
Yes, you can definitely do that in python.
Although, it opens a security hole, so be very careful.
You can easily do this by setting up a "loader" class that can collect the source code you want it to use and then call the exec builtin function, just pass some python source code in and it will be evaluated.
Check the package
http://opensourcehacker.com/2011/11/08/sauna-reload-the-most-awesomely-named-python-package-ever/ . It allows to overcome certain raw edges of plain exec. Also it may be worth to check Dynamically reload a class definition in Python

Creating a spec helper in rubymotion

I have some common methods used in a couple different specs, I want to extract them to some place like a spec helper that is accessible from all specs. Anyone know how to do this?
Here is something that sorta quacks like a spec_helper.
# _spec_helper.rb
module SpecHelper
::App::Persistence = {}
# global `before :each` ish
def self.extended(base)
base.before do
::App::Persistence.clear
end
end
def foo_helper
end
end
And then use it:
# my_view_spec.rb
describe "MyView" do
extend SpecHelper
before do
foo_helper
end
...
Two things to bear in mind:
Spec helper file is named in such way that it gets loaded first (leading underscore)
When running individual specs (e.g. files=my_view_spec.rb) helper file must go along - files=spec/my_view_spec.rb,spec/_spec_helper.rb
I just throw my common methods used in specs as they are (not encapsulated in a Module or anything) in a spec/support/utilities.rb file and Rubymotion seems to pick them up fine, though I don't know if this is the "proper" way to do this.
According to current http://www.rubymotion.com/developer-center/articles/testing/#_spec_helpers
Spec helpers are created under the spec/helpers directory of a RubyMotion project. An example could be spec/helpers/extension.rb.

Getting echofunc.vim to work

I came across echofunc.vim today (from a link in SO). Since I'm rubbish at remembering the order of function parameters, it looked like a very useful tool for me.
But the documentation is a bit lean on installation! And I've not been able to find any supplementary resources on the internet.
I'm trying to get it running on a RHEL box. I've copied the script into ~/.vim/plugin/echofunc.vim however no prompt when I type in a function name followed by '('. I've tried adding
let g:EchoFuncLangsUsed = ["php","java","cpp"]
to my .vimrc - still no prompting.
I'm guessing it needs to read from a dictionary somewhere - although there is a file in /usr/share/vim/vim70/ftplugin/php.vim, this is the RH default and does not include an explicit function list.
I'm not too bothered about getting hints on the functions/methods I've defined - just trying to get hints for the built-in functions. I can see there is a dictionary file available here which appears to provide the resources required for echofunc.vim, I can't see how I set this up.
TIA,
It expects a tags file, the last line of the description describes exactly how to generate it:
ctags -R --fields=+lS .
It works here with PHP but not with JS. Your mileage may vary.
I didn't know about this plugin, thanks for the info.
You should try phpcomplete.vim, it shows a prototype of the current function in a scratchpad. It is PHP only, though.

Resources