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:
! MarkdownPreview()
function
<< EOF
python
import vim
import subprocess
= "/home/osa1/Desktop/vim-markdown-preview/GeckoRenderer.py"
gr "python", gr, "\n".join(vim.current.buffer[:])])
subprocess.Popen([
EOF endfunction
Burda 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
= "ohnoes.pid"
PIDFILE = 8081 # dinleyecegimiz port, musait bir port olsun yeter
PORT = 1
DELAY
def run(text):
# burda birseyler yapilacak
= PORT
port = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # udp
s "", port)) # localhost'da 8081'i dinleyecegiz
s.bind((# burasi onemli, DELAY surede bir dinlemeyi birakip,
# arayuzu guncellenmeye zorlayacagiz
s.settimeout(DELAY)while True:
try:
= s.recvfrom(1024) # dinleme
data, addr except socket.timeout: # delay sure bekledik, birsey yok
print "timeout"
else:
print "got data", str(data) # veriyi aldik
# guncelleme fonksiyonumuzu cagirdik
update(data)
# 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:
"running") # dosyanin icerigi onemli degil
f.write(return False
if __name__ == "__main__":
= argv[^1] if is_running(): # program calisiyor
text = PORT
port = "localhost"
host = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # udp
s "", 0))
s.bind((# veriyi gonder
s.sendto(text, (host, port)) else:
# bu asamaya gelindiginde, is_running() zaten gerekli
# dosyayi olusturmus oluyor
= run(text) # program calistiriliyor
task next) # gtk musait oldugunda bunu cagiracak
gobject.idle_add(task. 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.