osa1 feed

Sublime Text ile blog yazmak

March 5, 2012 - Tagged as: tr.

TL;DR: Stajda canınız sıkılırsa çok gereksiz işler yapabiliyorsunuz :P . TL;DR 2: Sublime Text süper.

Cuma günü iş çıkışına yakın, Sublime Text 2 editorünü keşfettim. Nerden karşıma çıktı hatırlamıyorum. Görsel olarak çok hoş, kendi vim eklentisi var ve benim kullandığım bariz bir şekilde en hızlı editor. Yetmezmiş gibi bir de kendisi C++ ile geliştirilmiş olmasına rağmen Python ile eklenti yazılmasına olanak sağlıyor(bkz. Boost.Python). Vim olmadan düz metin bile yazamayan biri olarak hastası oldum tabii hemen.

Akşam biraz Python API’ını kurcalamaya başladım. Yeni bir editor sayılır ama şimdiden ~180 plugin var. Bir çoğu benim birazdan anlatacağım gibi geyik şeyler ama aralarında pek çok dilin REPL’ine bağlanabilmeyi sağlayacan SublimeREPL gibi süper projeler de var.

API o kadar basit ve küçüktü ki ilk birkaç saatte bir plugin yapabildim. IRC odalarına kod yapıştırmak için kullandığım LodgeIt için bir plugin yazdım. Kod içerisinde nereyi yapıştırmak istiyorsanız seçiyorsunuz, sağ tıklayıp yapıştır diyorsunuz ve LodgeIt sayfası açılıyor.

Bugün de blog yazma işini kolaylaştırmak için bir değişiklik yaptım. Artık blog yazılarımı Sublime Text 2 ile yazıyorum, F7 ile markdown’dan html render edip bakıyor, F8 ile sayfaya ekliyorum.

Daha önceden yazı ekleme işlerini yine kendi yazdığım bir arayüzle yapıyordum, arayüzün yaptığı mechanize ile Django admine login olup yazıyı eklemekti. Yazıyı ekledikten sonra programı kapatırsam bir daha güncelleyemiyordum. Django admin değişirse programı güncellemem gerekecekti. Bu sefer blogda bir değişiklik yaparak yeni bir view fonksiyonu ekledim:

def add_post(request):
    post_data = request.POST
    user = authenticate(username=post_data['username'], password=post_data['password'])
    json_response = {"result": "fail"}
    if user is not None and user.is_active:
        if post_data.has_key('id'):
            post = Post.objects.get(id=post_data['id'])
            for attr in post_data:
                if attr != "username" and attr != "password":
                    post.__setattr__(attr, post_data[attr])
            post.save()
            json_response["result"] = "update post"
            json_response["id"] = post.id
        else:
            # crate new post
            required_fields = set(["title", "verbose_name", "short", "post"])
            for attr in post_data:
                if attr != "username" and attr != "password":
                    required_fields.add(attr)
            try:
                p = Post(**{key : post_data[key] for key in required_fields})
                p.save()
                json_response["result"] = "new post"
                json_response["id"] = p.id
            except MultiValueDictKeyError as err:
                # in case of some required fields are missing
                json_response["result"] = str(err)
    return HttpResponse(json.dumps(json_response), mimetype="application/json")

HTTP POST methodu ile, kullanıcı adımı, şifremi, ve değişiklik yapmak istediğim veya eklemek istediğim yazının bilgilerini gönderiyorum ve duruma göre yazı ekleniyor veya varolan bir yazı güncelleniyor. Cevap olarak JSON formatında birkaç veri döndürüyor. Örneğin eklenen yazının id’si. Daha sonra Sublime Text için yazdığım eklenti bu id’yi sayfanın başına ekliyor ve bir daha F8 yaptığımda bu sefer daha önceden eklemiş olduğum yazı güncelleniyor. Küçük bir scriptle veritabanındaki tüm yazıları bu formatta kaydettim ve artık istediğim yazıyı tamamen Sublime Text ile güncelleyebiliyorum(sanki çok yazı güncelliyormuşum gibi hehe).

Sublime Text 2 eklentisi şöyle birşey:

class PostBlogCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        file_path = self.view.file_name()
        print "file_path:", file_path
        popen = subprocess.Popen(["blogpost", file_path],
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        result, error = popen.communicate()
        if error:
            self.view.set_status("Blog", "Error: " + error)
        else:
            d = json.loads(result)
            if d["result"] == "new post":
                self.view.insert(edit, 0, "#%s\n\n" % d["id"])
            self.view.set_status("Blog", d["result"])
        sublime.set_timeout(self.clean_statusbar, 5000)
    def clean_statusbar(self):
        self.view.erase_status("Blog")

Yaptığı şey kendi kendi yazdığım blogpost adlı programa dosyanın konumunu gönderip çıktısına göre Sublime Text’de statusbarda gerekli notları göstermek. blogpostda anlaşılabileceği gibi konumunu gösterdiğim dosyayı blog yazısı olarak siteye ekliyor. Kendime göre bir format oluşturdum(boş olmayan ilk satır başlık olacak vs. gibi).

Bu arada yazmayı unutmuşum, eklenti geliştirme işlemi de saçma derecede hızlı. Ne dosyası olursa olsun(kısayol tuşu ayarlayan dosyalar, menuleri ayarlayan dosyalar falan hep farklı) kaydettiğiniz an editor güncelleniyor ve bu neredeyse anlık bir işlem. ctrl+` ile Python editorün Python shell’ini açıp eklentilerinizi debug edebiliyor, API’ı inceleyebiliyorsunuz.

Lisp işleri için tabii ki Emacs’den vazgeçemem Python ve Haskell işlerim için artık Sublime Text ile devam edeceğim sanırım. Böyle basit bir API ve Python ile eklenti yazabilmek iyiymiş :) .