How to use function `write-region`? - file

I try to make a new file, according to this question and answer: How to create an empty file by elisp?
I copied the code
(write-region "" nil custom-file)
into a new emacs file and wanted to execute it by C-x C-e. But all i get is
Wrong type argument: stringp, nil
So what am i doing wrong here ? Im pretty new to emacs and have tried finding a solution by googling it but had no success.

Sounds like the value of custom-file is nil. It should be a string (that names a file).
If you set variable debug-on-error to t then you'll get a backtrace that will show you which arg that was expected as a string is actually nil.
Try wrapping your (relative) file name in expand-file-name, like this:
(write-region "" nil (expand-file-name "new_file"))
Now it should create the file in the current default-directory.
It also makes a difference where your cursor is, when executing C-x C-e. Put it at the end of the document.

Related

writing filenames into an array in Python

I read the files in a directory using glob, and then I rename each file to something more legible for my purposes using os.rename.
for file_name in glob.glob(path+'*.txt'):
newfilename = 'run'+str(i)+'.csv' # rename filenames to something more readable
os.rename(file_name,path + newfilename) #put r before path if error ="(unicode error) ‘unicodeescape’ codec can’t decode bytes in position 2-3: truncated \UXXXXXXXX escape"
When I try to write the each new file created into an array (a list) previously intialized to :
filelist=[];
using
filelist.append(i)=newfilename
I get the following error: "SyntaxError: cannot assign to function call"
If I just try to add the file to the filelst array using indeces, ie, filelist[i]=newfilename, I then get an index out of range error.
How do I do create this list of renamed filenames "on the fly"? Thank you.
Ok..so I finally understood that append wants to "append the "thing" to the list, as opposed to "append the thing at index i to the list" like I was trying to do originally.
So the correct way to use append is:
filelist.append(newfilename)

Advice on reading multiple text files into an array with Ruby

I'm currently writing out a program in Ruby, which I'm fairly new at, and it requires multiple text files to be pushed into an array line by line.
I am currently unable to actually test my code since I'm at work and this is for personal use, but I'm seeking advice to see if my code is correct. I knows how to read a file and push it to the array. If possible can someone check it over and advise if I have the correct idea? I'm self taught regarding Ruby and have no-one to check my work.
I understand if this isn't the right place for trying to get this sort of advice and it's deleted/locked. Apologies if so.
contentsArray = []
Dir.glob('filepath').each do |filename|
next if File.directory?(filename)
r = File.open("#{path}#{filename}")
r.each_line { |line| contentsArray.push line}
end
I'm hoping this snippet will take the lines from multiple files in the same directory and stick them in the array so I can later splice what's in there.
Thank you for the question.
First let's assume that 'filepath' is something like the target pattern you want to glob in Dir.glob('filepath') (I used Dir.glob('src/*.h').each do |filename| in my test).
After that, File.open("#{path}#{filename}") prepends another path to the already complete path you'll have in filename.
And lastly, although this is probably not the problem, the code opens the file and never closes it. The IO object provides a readlines method that takes care of opening and closing the file for you.
Here's some working code that you can adapt:
contentsArray = []
Dir.glob('filepath').each do |filename|
next if File.directory?(filename)
lines = IO.readlines(filename)
contentsArray.concat(lines)
end
puts "#{contentsArray.length} LINES"
Here are references to the Ruby doc's for the IO::readlines and Array::concat methods used:
https://ruby-doc.org/core-2.5.5/IO.html#method-i-readlines
https://ruby-doc.org/core-2.5.5/Array.html#method-i-concat
As an alternative to using the goto (next) the code could conditionally execute on files, like this:
if File.file?(filename)
lines = IO.readlines(filename)
contentsArray.concat(lines)
end

error in looping over files, -fs- command

I'm trying to split some datasets in two parts, running a loop over files like this:
cd C:\Users\Macrina\Documents\exports
qui fs *
foreach f in `r(files)' {
use `r(files)'
keep id adv*
save adv_spa*.dta
clear
use `r(files)'
drop adv*
save fin_spa*.dta
}
I don't know whether what is inside the loop is correctly written but the point is that I get the error:
invalid '"e2.dta'
where e2.dta is the second file in the folder. Does this message refer to the loop or maybe what is inside the loop? Where is the mistake?
You want lines like
use "`f'"
not
use `r(files)'
given that fs (installed from SSC, as you should explain) returns r(files) as a list of all the files whereas you want to use each one in turn (not all at once).
The error message was informative: use is puzzled by the second filename it sees (as only one filename makes sense). The other filenames are ignored: use fails as soon as something is evidently wrong.
Incidentally, note that putting "" around filenames remains essential if any includes spaces.

Opening Japanese-named files in Lua

I have bunch of XML files named in Japanese. I use Lua to read them and put the necessary informations into tables. I could open files named only in a single kanji like 名.xml, but for multiple kanjis like 名前.xml it was contrawise. Before I ran the Lua file, I set the command line's code page to 65001 (as UTF-8). And to read the files I need to encode the filename using WinAPI library from ACP (ASCII code page?) to UTF-8, but this encoding only works for the single kanjis. I've tried several suggestions across internet, using short path to the file, etc. but none of them worked. I tried to use the short path by running Lua as administrator--as stated in other similar question that you need administrator previleges to use the short path--but no luck.
...
for fn in io.popen("DIR xml /B /AA"):lines() do
...
local f = assert(io.open("xml\\" .. winapi.encode(winapi.CP_UTF8, winapi.CP_ACP, fn), "rb"))
...
end
...
But my code produced "Invalid argument" error. I searched this error but none of them are Lua-related, so I opened the C/C++-related ones, but what I got was only 'use _wfopen' or something like that. It's not implemented in Lua and neither I want to implement it myself. So anyone have any idea how to solve this? For more information just be sure to let me know. Thanks!
I don't know why your program does not work, but try this workaround:
local pipe = io.popen([[for %G in (xml\*) do #(type "%G" & echo #FILENAMEMARKER#%G)]], "rb")
local all_files = pipe:read"*a"
pipe:close()
for filecontent, filename in all_files:gmatch"(.-)#FILENAMEMARKER#(.-)\r?\n" do
-- process your file here
print('===== This is your file name:')
print(filename)
print('== This is your file content:')
print(filecontent)
print('== End of file')
end
I think you can use the Japanese alphabet in a table like
local jaAlphbet={"一","|","丶","ノ","乙","亅","<","二","亠","人","⺅","𠆢","儿","入","ハ","丷","冂","冖","冫","几","凵","刀","⺉","力","勹","匕","匚","十","卜","卩","厂","厶","又","マ","九","ユ","乃","𠂉","⻌","口","囗","土","士","夂","夕","大","女","子","宀","寸","小","⺌","尢","尸","屮","山","川","巛","工","已","巾","干","幺","广","廴,"廾","弋","弓","ヨ","彑","彡","彳","⺖","⺘","⺡","⺨","⺾","⻏","⻖","也","亡","及","久","⺹","心","戈","戸","手","支","攵","文","斗","斤","方","无","日","曰","月","木","欠","止","歹","殳","比","毛","氏","气","水","火","⺣","爪","父","爻","爿","片","牛","犬","⺭","王","元","井","勿","尤","五","屯","巴","毋","玄","瓦","甘","生","用","田","疋","疒","癶","白","皮","皿","目","矛","矢","石","示","禸","禾","穴","立","⻂","世","巨","冊","母","⺲","牙","瓜","竹","米","糸","缶","羊","羽","而","耒","耳","聿","肉","自","至","臼","舌","舟","艮","色","虍","虫","血","行","衣","西","臣","見","角","言","谷","豆","豕","豸","貝","赤","走","足","身","車","辛","辰","酉","釆","里","舛","麦","金","長","門","隶","隹","雨","青","非","奄","岡","免","斉","面","革","韭","音","頁","風","飛","食","首","香","品","馬","骨","高","髟","鬥","鬯","鬲","鬼","竜","韋","魚","鳥","鹵","鹿","麻","亀","啇","黄","黒","黍","黹","無","歯","黽","鼎","鼓","鼠","鼻","齊","龠"}
print(jaAlphbet[1])--and you can call the letters, letter by letter
sorry but thats all i know about the subject you are talking about but i hope this helps

How do I serialize a variable in VimScript?

I wish to save a random Vim dictionnary, let's say:
let dico = {'a' : [[1,2], [3]], 'b' : {'in': "str", 'out' : 51}}
to a file. Is there a clever way to do this? Something I could use like:
call SaveVariable(dico, "safe.vimData")
let recover = ReadVariable("safe.vimData")
Or should I build something myself with only textfiles?
You can put to good use the :string() function. Test these:
let g:dico = {'a' : [[1,2], [3]], 'b' : {'in': "str", 'out' : 51}}
let str_dico = 'let g:dico_copy = ' . string(dico)
echo str_dico
execute str_dico
echo g:dico_copy
... so you can save the str_dico string as a line of a vimscript file (e.g. using writefile()), and then source the vim file directly.
Thanks to VanLaser (cheers), I've been able to implement these functions using string, writefile and readfile. This is not binary serialization but it works well :)
function! SaveVariable(var, file)
" turn the var to a string that vimscript understands
let serialized = string(a:var)
" dump this string to a file
call writefile([serialized], a:file)
endfun
function! ReadVariable(file)
" retrieve string from the file
let serialized = readfile(a:file)[0]
" turn it back to a vimscript variable
execute "let result = " . serialized
return result
endfun
Use them this way:
call SaveVariable(anyvar, "safe.vimData")
let restore = ReadVariable("safe.vimData")
Enjoy!
I used #iago-lito's answer in a script I wrote a few years ago. Yesterday I spent some time improving on it. The vim dictionary is very similar to a JSON object, but:
when I open the file and set filetype=json, the linter complains about the single quotes around the strings, and
the JSON formatter splits the text into multiple lines, and indents them to make a pretty file. As a result, reading only the 0'th line of text doesn't give a complete dictionary object.
Here are my modifications to fix both issues.
function! SaveVariable(var, file)
" Change all single quotes to double quotes.
" {'x':'O''Toole','y':['A',2,'d']} -> {"x":"O""Toole","y":["A",2,"d"]}
let serialized = substitute(string(a:var),"'",'"','g')
" Change all escaped double quotes back to apostrophes.
" {"x":"O""Toole","y":["A",2,"d"]} -> {"x":"O'Toole","y":["A",2,"d"]}
let serialized = substitute(serialized,'""', "'",'g')
call writefile([serialized], a:file)
endfunction
function! ReadVariable(file)
execute 'let result = [' . join(readfile(a:file),'') . ']'
return result[0]
endfunction
This seems to work well for all kinds of data. I tested it with an object, a list, and number and string scalar values.
STRANGER, DANGER!
Here is a word of warning that goes along with this and any other dynamically-generated code. Both #iago-lito's and my solution are vulnerable to code injection, and if you are reading files that are out of your control, bad things can happen to your machine. For example, if someone sneaks this into the file:
42|call system('rmdir /s /q c:\')|call system('rm -rf /')
calling #iago-lito's ReadVariable() will return 42, but your computer will be toast, whether it's a Windows, Mac, or Linux machine. My version also fails, albeit with a more complex version of the statement:
42]|call system('rmdir /s /q c:\')|call system('rm -rf /')|let x=[
A proper solution would be to parse the text, looking for the end of the actual data, and dumping everything after it. This means you lose the simplicity of this approach. Vim and Neovim have come a long way in recent years. lua and python are, from what I've read, easier than ever to integrate into vimscript. I wouldn't be surprised if either of those languages has a built-in answer to this question.

Resources