March 17, 2011 - Tagged as: python, tr.
Bloguma vim ile yazı yazma projemin bir parçası(aslında vim ile python scripti çağırmak ile alakalı yaptığım deneylerin bir sonucu olan) olan vim-markdown-preview scriptin sayesinde birkaç şey farkettim.
Vim için bir script yazacaksanız ve bu scriptin tek yapacağı buffer’daki metini alıp onunla birşeyler yapmaksa, bunun en basit yolu bir vimscriptiyle buffer’ı başka bir python scriptine göndermek sanırım. En azından ben öyle yaptım. Şu kadar basit:
function! MarkdownPreview()
python << EOF
import vim
import subprocess
gr = "/home/osa1/Desktop/vim-markdown-preview/GeckoRenderer.py"
subprocess.Popen(["python", gr, "\n".join(vim.current.buffer[:])])
EOF
endfunctionBurda farkedebileceğiniz gibi bufferı çekip, subprocess.Popen ile istediğiniz Python scriptine gönderebiliyorsunuz. Çok kolay, bundan sonrası da normal Python zaten.
Fakat burda şöyle bir problem oluşuyor, bu fonksiyonu her çağırdığınızda Python scripti bir daha çalışıyor. Benim yapmak istediğim, eğer script zaten çalışıyorsa onu güncellemek.
Burda iki problem var, birincisi, programın zaten çalışıp çalışmadığını tespit etmek, ikincisi de eğer zaten çalışıyorsa ona mesaj göndermek. İkisi hakkında da nette bir sürü çözüm var(dbus, pid, multiprocess, pipe, alakalı SO mesajları: 1, 2, 3, 4).
Fakat benim uyguladığım ve sanırım en basit yöntem, programın çalışmadan önce bir dosyayı kontrol etmesi, o varsa çalışmak yerine gerekli sunucunun(localhost) gerekli portuna mesaj göndermesi. Mesajlaşma olayını socketlerle hallettim yani. Çok kolay ve anlaşılır oldu. Fakat işin içine arayüz girince bir problem daha ortaya çıktı: bir socket dinlerken arayüzü güncellemek.
Aşağıdaki program herşeyi özetliyor:
import os
import gtk
import socket
import gobject
from sys import argv
# dosya adi farketmez, programimiza ait oldugu belli olsun
PIDFILE = "ohnoes.pid"
PORT = 8081 # dinleyecegimiz port, musait bir port olsun yeter
DELAY = 1
def run(text):
# burda birseyler yapilacak
port = PORT
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # udp
s.bind(("", port)) # localhost'da 8081'i dinleyecegiz
# burasi onemli, DELAY surede bir dinlemeyi birakip,
# arayuzu guncellenmeye zorlayacagiz
s.settimeout(DELAY)
while True:
try:
data, addr = s.recvfrom(1024) # dinleme
except socket.timeout: # delay sure bekledik, birsey yok
print "timeout"
else:
print "got data", str(data) # veriyi aldik
update(data) # guncelleme fonksiyonumuzu cagirdik
# bu sekilde gtk'yi guncellenmeye zorluyoruz
while gtk.events_pending():
gtk.main_iteration()
# surekli True dondurerek gtk'ya islemin bitmedigini soyluyoruz
# musait oldugunda yine bu fonksiyonu cagirsin
yield True
def is_running():
# Pid'e falan hic gerek yok,
# bir dosya olusturup, onu kontrol edecegiz
# program acilirken o dosyayi olusturacak,
# kapanirken silecek, sorun yok
if os.path.isfile(PIDFILE):
return True # program zaten calisiyor
with file(PIDFILE, "w") as f:
f.write("running") # dosyanin icerigi onemli degil
return False
if __name__ == "__main__":
text = argv[^1] if is_running(): # program calisiyor
port = PORT
host = "localhost"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # udp
s.bind(("", 0))
s.sendto(text, (host, port)) # veriyi gonder
else:
# bu asamaya gelindiginde, is_running() zaten gerekli
# dosyayi olusturmus oluyor
task = run(text) # program calistiriliyor
gobject.idle_add(task.next) # gtk musait oldugunda bunu cagiracak
gtk.main()Kodda bulunmayan ama dikkat edilmesi gerek bir nokta da, gui’nin kapanma fonksiyonuna(close sinyali gönderildiğinde çağırılan fonksiyon) os.remove(PIDFILE) satırını eklenmesi. Ha unutmadan, dosya konumu değiştirilmeli tabii ki, bu halde program halgi dizinden çağırılıyorsa oraya bakıyor ve gerekiyorsa dosyayı oluşturuyor.