Sys.stdin'i eş zamanlı olarak renklendirmek

Merhaba arkadaşlar,
Python kodlarını ve modüllerini çalıştıran, görsel bir stili olan bir konsol programı yazmaya çalışıyorum.


Program şu anlık stdout’u yeşil renkte, stderr’i kırmızı renkte ve stdin’i beyaz renkte gösteriyor.
stdin’in renklendirilmesi, stdout veya stderr’ın renklendirilmesi ile yapılıyor.
Ancak yapmak istediğim, Python’ın özel anahtar kelimelerinin özel bir renkle, tuşlara basılır basılmaz renklenmesi.
Bunun için bir keylogger kullanmayı düşündüm ancak henüz nasıl kullanmam gerektiğini bulamadım.

Kodlar:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import sys
import colorama

CODE = ""
SIZE = 0
TAB = " " * 4

colorama.init(autoreset=False)
sys.stdout.write(colorama.Fore.WHITE)

while True:
    if SIZE >= 1:
        LINE = input("... {}".format(TAB * SIZE))
        CODE += "{}{}\n".format(TAB * SIZE, LINE)
        if LINE == '':
            if SIZE == 0:
                try:
                    sys.stdout.write(colorama.Fore.GREEN)
                    exec(CODE)
                    sys.stdout.write(colorama.Fore.WHITE)
                except BaseException as ERR:
                    sys.stderr.write("{}{}\n".format(colorama.Fore.RED, ERR))
                    sys.stdout.write(colorama.Fore.WHITE)
                CODE = ""
                SIZE = 0
            else:
                SIZE -= 1
                continue

        elif LINE.endswith(":"):
            SIZE += 1
        else:
            continue
    else:
        LINE = input(">>> {}".format(TAB * SIZE))
        CODE += "{}{}\n".format(TAB * SIZE, LINE)
        if not LINE.endswith(":"):
            if LINE == "exit()" or LINE == "quit()":
                break
            elif LINE == "clear()":
                os.system("cls" if os.name == "nt" else "clear")
                CODE = ""
            try:
                sys.stdout.write(colorama.Fore.GREEN)
                exec(CODE)
                sys.stdout.write(colorama.Fore.WHITE)
            except BaseException as ERR:
                sys.stderr.write("{}{}\n".format(colorama.Fore.RED, ERR))
                sys.stdout.write(colorama.Fore.WHITE)
            CODE = ""
            SIZE = 0
        else:
            SIZE += 1

Bu konuda yardımcı olabilecek arkadaşlar varsa yardımlarını esirgemezlerse sevinirim.

Not: IPython’da renklendirme işlemi otomatik olarak yapılıyor, ama bu program için yapılabilir mi, yapılırsa nasıl yapılır öğrenmek istiyorum.

1 Beğeni

Merhaba.

Uzaklarda keylogger aramanıza gerek yok, Python’ın standart kütüphanesi içinde mevcut: https://docs.python.org/3/library/msvcrt.html#msvcrt.getch Bu Windows için. UNIX sistemleri için şu adresteki gibi basit bir şekilde bu fonksiyonu gerçekleyebilirsiniz: http://code.activestate.com/recipes/134892-getch-like-unbuffered-character-reading-from-stdin/

Girdileri karakter karakter aldıktan sonra belirli noktalarda renklendirme için Python ile yazılmış olan Pygments’e bakabilirsiniz. Tabii Pygments’ten colorama ya da genel olarak terminale için çıktı veren bir paket bulmanız gerekebilir.

Eğer “Token’larına ben ayırır sonra kendim renklendiririm.” diyecek kadar cesursanız tokenize modülüne bakmanızı öneririm. :grin: Zor ama eğlenceli; kolay gelsin. :grinning:

Bu arada şurada dediğinizi yapan bir paket mevcut: https://bpython-interpreter.org/

İyi çalışmalar.

1 Beğeni

Kimi zaman eğlenceli, kimi zaman sinir edici ve zor evet. :slight_smile: Bu arada linklere bakacağım, teşekkür ederim. Acaba keyword sorgusu yaparak renklendirme yapılabilir mi diye düşünüyordum…

Bundan kastınız nedir tam olarak?

import keyword

KWLIST = keyword.kwlist


# >>> def diye kodları yazarken
# def'e benzeyen ifadelerden def'i ayırmayı düşünüyordum:
# belki backspace ile tuş kombinasyonlarını birbirinden ayırarak.
# def yazdığımız zaman def renklenecek ama defter
# yazdığımız zaman herhangi bir değişiklik olmayacak.
# tuşlara bastığımız zaman, tuşlar bir listeye kaydedilecek.
# backspace ile def karakterlerinin hangi ifadeye ait olduğu
# ayırt edilebilir mi diye düşünüyordum.
# iki backspace arasında kalan ifade eğer keyword ise, şu şu
# işlemler yapılacak; fonksiyon ise şu şu işlemler yapılacak,
# bunlardan biri değilse de şu şu işlemler yapılacak.
# Bu yaklaşıma zıt bir düşünce de geldi aklıma:
# iki backspace arası ya stringin içinde geçiyorsa?
# o zaman iki tırnak arasında bu işlem geçerli olmamalı.
# bunları bir çözmek lazım.
...
    if keyword.iskeyword(i):
       ...
    elif callable(i):
       ...
# Bahsettiğim bu teorik işlemlerin yukarıdaki ilk mesajdaki kodların
# neresine nasıl dahil edeceğimi daha bulamadım. 

Keylogger ile stdin’e girilen her karakterin keyword listesinde olup olmamasıyla veya bu karakterlerin bir fonksiyon olup olmamasıyla ilgilenen bir işlem tanımlamayı ve şayet stdindeki karakter topluluğu bu listede varsa veya yazı bir fonksiyonsa nasıl renklendirilebileceğini düşünüyordum.

Benim yampak isteyipde yapamadigim sey :slight_smile: yakinda bende ilgilenecem bu konuyla sizinde caliwmalrinizi merak ediyorum nasil bir sonuc ortaya cikacak

“Yapamamak” değil de “yapmamak” vardır bana göre; insan her istediğini yapabilecek güçtedir. :slightly_smiling_face:

Aslında tokenize modülü bu yapmak istediğinizi yapıyor. Kodu parçalarına ayırıyor ve bunu yapısal bir şekilde size veriyor. Anahtar sözcükleri nasıl ayırt edeceğim gibi konularda endişe etmenize gerek kalmıyor böylece. Ancak siz sanırım her işi kendiniz yapmak istiyorsunuz. :grinning: Bu durumda, örneğin, tokenize modülünün nasıl yazıldığına bakabilirsiniz. Ya da bir "lexer"ın nasıl yazılabileceğini araştırabilirsiniz. Eğer prosedürel bir şekilde(‘if’ ve 'for’lar ile) yazmaya çalışırsanız ortaya çıkan hatalarla fazlaca uğraşmak zorunda kalırsınız. Kuralları BNF(Backus-Naur Form) ya da düzenli ifadeler ile yazabilirsiniz. Programlama dillerinin kuralları genellikle BNF ile yazıldığı için BNF daha doğru bir seçim gibi görünüyor bana. Yine de düzenli ifadeler ile de yazılabilir diye düşünüyorum. Çünkü lexer’larda düzenli ifade kuralları görmüşlüğüm var. Sadece kuralları yazmak, gerisini yapmamak isterseniz şu projeye bir göz gezdirebilirsiniz: PLY (Python Lex-Yacc) Bu arada Flex(lexical analyser olan Flex) araştırmanızı tavsiye ederim. Biraz önce verdiğim proje bu aracın Python için yazılmış bir halidir. Daha fazla araştırarak alternatiflerini de bulabilirsiniz. Bahsettiğim kavramlar programlama dilleri yapımında kullanılan teknolojilerin bir kısmını belirtmekte. Yani yine eğlenceli ve zor. Kolaylıklar dilerim. :grin:

İyi çalışmalar.

2 Beğeni

Aslında nasıl bir işlemler sırası oluşturmam lazım onu kafamda oturtmaya çalışıyordum. tokenize modülü bu iş için kolaylık sağlıyorsa, tokenize modülünü inceleyip, gerekli yerde onu kullanmayı düşünürüm.

Bu konuda size katılıyorum. Bir sürü koşul tanımlamak gerekecek. Ve belki aklıma gelmeyen bir koşulu tanımlamadığım için hatalar ortaya çıkacak. Gerçi sonradan hatanın nereden kaynaklandığı ortaya çıkıyor ama kimbilir kaç kere yinelenecek bu işlem…
Şu tokenize modülünü iyice bir inceleyeyim önce. Kullanabilirsem onu kullanırım yoksa başka bir çare düşünmeye çalışacağım.

Koşullar tek tek tanımlanacaksa düzenli ifadelerin yardımına ihtiyacımız olabilir evet. Neyse dediğiniz gibi biraz araştırayım konuyu. Ara ara başlığı günceller, sorular sorarım. :slight_smile:

Hım, bu konuyu da araştırmam lazım.

Yardımınız ve önerileriniz için çok teşekkür ederim,

1 Beğeni

@ismailarilik
İsmail Bey bir soru sormak istiyorum. Kodları daha parçalarına ayırma işlemine başlamadım ama kafama takılan konu aslında renklendirme işlemiyle alakalı. Diyelim kodlarda bulunan karakterlerin anahtar kelime veya fonksiyon olup olmamasıyla ilgilenen bir program yazdık, Peki bu durumda sys.stdin’i nasıl uyaracağız, o da tokenize modülüyle mi yapılıyor? Yani kullanıcı def yazdı, ayırt edici program da bunu algıladı, o an nasıl bir komut verip sys.stdin’in renklenmesini sağlarız? (Hey stdin! kullanıcı “def” yazdı, mavi renge bürün…)
Bu işlem standart kütüphanede bulunan bir modülle veya 3. parti başka bir modülle mi yapılır?

Merhaba. Çok fazla ödevim olduğu için pek uğraşamadım ama konuyu görünce dikkatimi çekti ve bir kaç deneme yapmak istedim. Şimdilik sadece def komutu çalışıyor. Tabi tam olarak istenilen şekilde değil. Belki geliştirilebilir. Programı açıp direkt olarak klavyeden d, e ve f tuşlarına basarsanız def’i sarı renk yapacak. Nasıl oluyor diyecek olursanız; bir not defteri oluşturuyor ve not defterine klavyeden basılan tuşları kaydediyor. Eğer basılan tuşlar def’e eşit olursa def’i sarı renk yazıyor.

from pynput.keyboard import Key, Listener
from colorama import init
from termcolor import colored

init()

def on_press(key):
    print(key)
    dosya = open('log_2.txt', 'a')
    dosya.write("{0}".format(key))
    dosya.close()

    oku = open('log_2.txt', "r")
    b = oku.readline()
    if(b == "'d''e''f'"):
        print(colored("def",'yellow'))
    else:
        print("None")

def on_release(key):
    if key == Key.esc:
        return False

with Listener(on_press=on_press, on_release=on_release) as listener:
    listener.join()

Merhaba.

Niye dosyaya yazma ihtiyacı duyduğunuzu anlamadım. Bir de karakter dizileri içindeki 'def’leri de renklendiriyor mu aynı şekilde?

Merhaba, teşekkür ederim.

Ancak sys.stdin renklenmedi.

Bu konu hakkında bir bilgim yok. Ancak şöyle bir düşününce kontrol karakterleri ile yapılabilir diye düşünmekteyim. Örneğin; \r(carriage return) karakteri satırın başına gidilmesini sağlıyor. Ki günlük hayatta da aynı satırda değişiklik yapan(mesela bitme durumu yüzdesini gösterme) programlar görüyorum. Onlar yazıyı değiştiriyor ama rengi değiştirmek de mümkündür diye düşünüyorum.

Hım, evet doğru, “\r” belki yardımcı olabilir. Deneyip göreyim. (Ama stdout için kullanılabiliyordu o). stdin.write() komutu olmadığı için “\r”'yi stdin’e nasıl ilave ederiz, edilebilir mi bakmak lazım.

Muhtemelen evet. Çünkü basit olarak ekrana def yazılırsa bunu sarı yap gibi bir işlem uyguladım. Not defterine yazma amacım ise anlamadığım bir şekilde karşılaştırma yapamamıştım basılan tuşları. Yani d, e ve f tuşlarına basılırsa sarı yazmıyordu. Not defterine yazılan yazı ile karşılaştırma yapmam gerekti bu yüzden.

Açıkçası bu çok basit bir örnek. Tek kullanımlık yani. def yazarken arada farklı bir tuşa da basarsanız kabul etmeyecektir. Not defterini silip hatasız olarak tekrar denerseniz çalışacaktır. Dediğim gibi çok basit bir örnek. Ne kadar faydalı olur sizin için bilemem.

Heh şimdi oldu, hata benden kaynaklıymış. Ancak var olan defi sarı yapmıyor. def yazıyoruz, yeni bir satırda sarı bir def print ediyor, yani sys.stdout renkleniyor, sys.stdin değil. Yine de ilginiz için teşekkür ederim. Biraz araştırayım konuyu. Birşeyler buldukça bu başlığa eklemelerde bulunurum.

Haklısınız. Aklıma gelen ilk şeyi denemiştim. Açıkçası bu konu hakkında o yaptığımdan ileri gidemem şu anki Python bilgimle. Size iyi çalışmalar. :slight_smile:

1 Beğeni

Olsun, sağolun. Size de iyi çalışmalar. :slight_smile:

Bu arada geçen yeni bir şey öğrendim. Acaba bu programı exe’ye çevirsek, Python yüklü olmayan, işletim sistemi windows olan bir bilgisayarda çalışacak mı düşüncesiyle exe’ye çevirdim ve çalıştı. Ayrıca programa üçüncü parti modülleri dahil edip (başka dosyalara bağımlılığı fazla olan modüllerin dll dosyalarını da eklemek gerekiyor olabilir.) exe’ye çevirebiliyoruz. Programa modül ekledikçe boyutu da haliyle artıyor. Şu sys.stdin de renklendirilebilirse, hoş bir Python programı olacak diye umuyorum.

stdin’e yazmak biraz sıkıntılı olabilir; çünkü stdin veri okumak için, yazmak için değil. En başta stdin dosya benzeri(file-like) bir nesne olarak ayarlanabilir. O zaman o dosyadan okur. Ama aynı zamanda kullanıcıdan da veri alınabilmesi gerek. Bu durumda aklıma klavye tuşlarına programatik olarak basmak geliyor. Tabii performansına da bakmak gerekiyor; kullanıcı metin girerken kasma hissetmemeli.