Code Copy代码拷贝进一个文件工具

Code Copy代码拷贝进一个文件工具,第1张

前言

交毕设居然要求要把代码拷贝到word文档上???
什么神奇 *** 作,而我的毕设代码量似乎六七千行,这不得累死…
还是写个脚本吧,说干就干!

本来计划很美好,结果执行起来后写出却是阉割版…
(treeview监听事件后不知道怎么只让子类处理…菜鸡菜鸡,要是像vue那么方便就好了, messagebox居然在mac上老是warning…)

该脚本只需要python环境即可,安装的见我另一篇博文Python环境配置与入门建议(面向新手文)



界面

选了一个文件夹当例子

导出后:

by the way, 若你想保留缩进的话,可以做以下更改(只是我自己有些代码层数多,缩进多了之后行的空间不太够,所以直接就去掉缩进了)



拷贝到word后,只需要搜索 【代码文件】就能找到每一个拷贝的文件名了,然后就可以设置一下 标题,我想了想,还是要把这个选择留给用户去做,因为我不太清楚你想把这个文件定义为第几级标题。

宽度不够中间那一条线可用鼠标拖动过去



用户自定义区

代码
"""
Author: Andy Dennis
Date: 2022.5.14, SAT
Last Alter Time: 16:36, 2022.5.14
"""
import tkinter as tk
from tkinter import filedialog
from tkinter import ttk
import os
import tkinter.font as tf
from threading import Thread


# ---> 自定义区 start, 供用户自定义修改
file_decoration_prefix = '代码文件'    # 文件名前缀
count_lines_with_null_string = False  # 计算代码行数时是否考虑空行
put_null_string_to_txt = False        # 是否把空行也复制进文档
# 不参与计算的文件类型
ignore_file_type = ['pt',
                    'png', 'jpg', 'jpeg', 'pdf', 'ico',
                    'doc', 'docx', 'ppt', 'pptx', 'csv', 'xls', 'xlsx']
# 代码注释样式, {}代表注释内容, 默认 //, 该注释会放在文件开头,作为文件开始的标识
annotation_map = {'html': '',
                  'css': '/* {} */',
                  'py': '# {}',
                  'vue': ''}
# 忽略的文件
ignore_name_lt = ['.DS_Store', '__pycache__']
# <--- 自定义区 end

# 全局变量
dir_path = ''                   # 工作目录
code_lt = []
code_file_nums = 0
code_file_lines = 0


# txt文本读取出来后,返回列表
def read_txt_lines(fp_):
    # print('!!! ', fp_)
    with open(fp_, "r", encoding='utf-8') as f:  # 打开文件
        data = f.readlines()
    data = [item.strip() for item in data]
    return data


# 列表转txt文本
def write_lt2txt(lt, fp_):
    lt = [i + '\n' for i in lt]
    with open(fp_, 'w', encoding='utf-8') as f:
        f.writelines(lt)
    print('写入到 {} 文件成功'.format(fp_))


def insert_item(tree_root, tree_p, path_p):
    """
    递归在树状目录中插入显示文件结构, 深度优先
    tree_root: 树状表格根节点, 
    tree_p: 父类根节点,
    path_p: 目录名字
    """
    dir_lt = os.listdir(path_p)
    for item_index, item_name in enumerate(dir_lt):
        if item_name in ignore_name_lt:   # 跳过一些文件
            continue

        item_path = '{}/{}'.format(path_p, item_name)
        if os.path.isdir(item_path):
            tree_new = tree_root.insert(
                tree_p, item_index, text="{}".format(item_name))
            insert_item(tree_root, tree_new, item_path)
        else:
            tree_new = tree_root.insert(
                tree_p, item_index, text="{}".format(item_name))


# 清空树状目录
def clearTreeView(tree_node):
    x = tree_node.get_children()
    for item in x:
        tree_node.delete(item)


def copy_file_recurrent(abs_path_p, path_p):
    """
    递归拷贝文件代码, 深度优先
    tree_root: 树状表格根节点, 
    tree_p: 父类根节点,
    path_p: 目录名字
    """
    global code_lt
    global code_file_nums
    global code_file_lines
    # global ignore_file_type
    # global file_decoration_prefix        # 文件名前缀
    # global count_lines_with_null_string  # 计算代码行数时是否考虑空行
    # global put_null_string_to_txt        # 是否把空行也复制进文档

    dir_lt = os.listdir(abs_path_p)
    for item_name in dir_lt:
        item_abs_path = '{}/{}'.format(abs_path_p, item_name)
        if len(path_p) > 0:
            tmp_path = '{}/{}'.format(path_p, item_name)
        else:
            tmp_path = item_name
        if os.path.isdir(item_abs_path):
            copy_file_recurrent(item_abs_path, tmp_path)
        else:
            if item_name in ignore_name_lt:  # 跳过忽略的文件
                continue

            item_type = item_name.split('.')[-1]
            # print('@@@ item_type', item_type, item_type in ignore_file_type)
            # print(ignore_file_type)
            if item_type not in ignore_file_type:
                code_file_nums += 1
                code_lt.append('{}'.format(item_name))
                anaotation_template = annotation_map.get(item_type, '// {}')
                code_lt.append(anaotation_template.format(file_decoration_prefix + ' ' + tmp_path))

                tmp_lt = read_txt_lines(item_abs_path)

                for line_str in tmp_lt:
                    if len(line_str) > 0:
                        code_lt.append(line_str)
                        code_file_lines += 1
                    else:
                        if put_null_string_to_txt:
                            code_lt.append(line_str)
                        if count_lines_with_null_string:
                            code_file_lines += 1


# 选择文件线程 *** 作
def select_work_dir_worker():
    global dir_path
    clearTreeView(tree_root)

    fp = filedialog.askdirectory(title=u'选择目标目录')
    if fp is not None and len(fp) > 0:
        dir_path = fp
        insert_item(tree_root, "", dir_path)

        tmp_path = fp
        if tmp_path[0] == '/':
            tmp_path = tmp_path[1:]   # mac下默认/开头
        tmp_path = tmp_path.replace('\', '/').split('/')
        if len(tmp_path) > 4:
            tmp_path = tmp_path[-4:]
            tmp_path.insert(0, '...')
        else:
            tmp_path.insert(0, '')
        tmp_path = '/'.join(tmp_path)

        label1['text'] = 'work dir: {}'.format(dir_path)
        label2['text'] = 'tips: 选择了 {}'.format(tmp_path)
        label3['text'] = ''
    else:
        label2['text'] = 'tips: 您取消了选择 工作目录  *** 作.'


# 拷贝代码线程工作
def copy_code_op_worker():
    global code_lt
    global code_file_nums
    global code_file_lines

    if len(dir_path) == 0:
        label2['text'] = 'tips: 请您先选择工作目录.'
        return

    # 清零工作
    code_lt.clear()
    code_file_nums = 0
    code_file_lines = 0
    copy_file_recurrent(dir_path, '')

    # print(code_lt)
    print('代码文件: {}, 代码行数: {}'.format(code_file_nums, code_file_lines))
    # print('copy_code_op')
    fp = filedialog.asksaveasfilename(defaultextension='.txt')
    if fp is not None and len(fp) > 0:
        write_lt2txt(code_lt, fp)
        tmp_path = fp.replace('\', '/')
        if tmp_path[0] == '/':
            tmp_path = tmp_path[1:]   # mac下默认/开头
        tmp_path = tmp_path.split('/')
        if len(tmp_path) > 4:
            tmp_path = tmp_path[-4:]
            tmp_path.insert(0, '...')
        else:
            tmp_path.insert(0, '')
        tmp_path = '/'.join(tmp_path)

        label2['text'] = '导出到 {}'.format(tmp_path)
        label3['text'] = '代码文件个数: {}, 代码行数: {}'.format(
            code_file_nums, code_file_lines
        )
    else:
        label2['text'] = 'tips: 您取消了 代码拷贝  *** 作.'
    
    code_lt.clear()
    code_file_nums = 0
    code_file_lines = 0


# 线程类
class MyThread(Thread):
    def __init__(self, func):
        """
        :param func: 可调用的对象
        """
        Thread.__init__(self)
        self.func = func
    
    def run(self):
        self.func()


# 线程工厂
def work_factory(func):
    t = MyThread(func)
    t.start()
    # t.join()


# 选择工作目录 *** 作
def select_work_dir():
    work_factory(select_work_dir_worker)


# 拷贝代码 *** 作
def copy_code_op():
    work_factory(copy_code_op_worker)


if __name__ == '__main__':
    window = tk.Tk()
    window.title("Code Copy v1")    # #窗口标题
    window.geometry("600x468")   # #窗口位置500后面是字母x

    bt1 = tk.Button(window, text='选择目录', width=16, height=1,
                    font=tf.Font(size=14), command=select_work_dir)
    bt1.place(x=100, y=30)
    bt2 = tk.Button(window, text='拷贝代码', width=16, height=1,
                    font=tf.Font(size=14), command=copy_code_op)
    bt2.place(x=350, y=30)

    label1 = tk.Label(window, text="请选择工作目录".format(dir_path))
    label1.place(x=40, y=64)

    label2 = tk.Label(window, text="")
    label2.place(x=40, y=420)

    label3 = tk.Label(window, text="")
    label3.place(x=40, y=440)

    '''
    树状结构
    '''
    tree_root = ttk.Treeview(window, height=16, columns='code')
    tree_root.place(x=100, y=100)


    # 不允许重新设置大小
    window.resizable('false', 'false')
    window.mainloop()   # #窗口持久化

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/langs/943132.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-18
下一篇 2022-05-18

发表评论

登录后才能评论

评论列表(0条)

保存