0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

as2js

Posted at

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Threading;

namespace AS2JS
{
public partial class MainWindow : Window
{
private string _lastInputFilePath = null; // 마지막으로 읽어들인 .as 파일 경로
private bool _isSyncing = false; // 스크롤 동기화 중복 호출 방지 플래그

    // ─────────────────────────────────────────────────────────────────────
    // 1) 변환 규칙 정의용 클래스
    private class TransformRule
    {
        public Regex Pattern;       // 매칭할 정규식
        public string Replacement;  // 치환할 문자열
    }

    // 2) ActionScript → JavaScript 변환 규칙 목록
    //    필요한 만큼 항목을 추가하면 됩니다.
    private static readonly List<TransformRule> _rules = new List<TransformRule>
    {
        new TransformRule {
            Pattern     = new Regex(@"\bvar\s+(\w+):\w+\s*=", RegexOptions.Compiled),
            Replacement = "let $1 ="
        },
        new TransformRule {
            Pattern     = new Regex(@"\btrace\s*\(", RegexOptions.Compiled),
            Replacement = "console.log("
        },
        // 예시: 클래스/함수 변환 규칙 추가 방법
        // new TransformRule {
        //     Pattern     = new Regex(@"\bfunction\s+(\w+)\s*\(", RegexOptions.Compiled),
        //     Replacement = "$1("
        // },
        // new TransformRule {
        //     Pattern     = new Regex(@"\bclass\s+(\w+)\b", RegexOptions.Compiled),
        //     Replacement = "class $1"
        // },
    };

    public MainWindow()
    {
        InitializeComponent();
    }

    // 드래그 중 커서 처리 (복사 모양 유지)
    private void Window_PreviewDragOver(object sender, DragEventArgs e)
    {
        e.Effects = DragDropEffects.Copy;
        e.Handled = true;
    }

    // 파일 드롭 이벤트 핸들러
    private void Window_Drop(object sender, DragEventArgs e)
    {
        if (!e.Data.GetDataPresent(DataFormats.FileDrop)) return;

        var files = (string[])e.Data.GetData(DataFormats.FileDrop);
        if (files.Length == 0 || Path.GetExtension(files[0]).ToLower() != ".as") return;

        _lastInputFilePath = files[0];

        // 1) Shift-JIS로 .as 파일 읽기
        string asText = File.ReadAllText(_lastInputFilePath, Encoding.GetEncoding(932));
        var asLines = asText.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);

        // 2) 각 줄을 변환하면서 하이라이트 범위 계산
        var converted = asLines
            .Select(line => ConvertLineWithSpans(line))
            .ToList();

        // 3) 원본 AS 코드 표시
        AsRichTextBox.Document.Blocks.Clear();
        foreach (var line in asLines)
            AsRichTextBox.Document.Blocks.Add(new Paragraph(new Run(line)));

        // 4) 변환된 JS 코드 + 하이라이트 표시
        JsRichTextBox.Document.Blocks.Clear();
        foreach (var cl in converted)
            JsRichTextBox.Document.Blocks.Add(BuildParagraphFromSpans(cl));

        // 5) 드롭 직후에 스크롤 싱크 설정
        Dispatcher.BeginInvoke(new Action(SyncScroll), DispatcherPriority.ApplicationIdle);
    }

    // ─────────────────────────────────────────────────────────────────────
    // DTO: 변환된 텍스트와 하이라이트 스팬(시작위치, 길이) 저장용
    private class ConvertedLine
    {
        public string Text;
        public List<(int Start, int Length)> Spans;
    }

    // 3) 한 줄을 규칙에 따라 변환하고, 치환된 부분만 스팬으로 기록
    private ConvertedLine ConvertLineWithSpans(string original)
    {
        string working = original;
        var spans = new List<(int, int)>();

        foreach (var rule in _rules)
        {
            // 매치되는 모든 부분 찾기
            var matches = rule.Pattern.Matches(working).Cast<Match>().ToList();
            int offset = 0;

            foreach (var m in matches)
            {
                // 치환 결과 문자열
                string rep = m.Result(rule.Replacement);

                // 치환 전 위치 + 이전 오프셋
                int start = m.Index + offset;
                spans.Add((start, rep.Length));

                // 오프셋 보정
                offset += rep.Length - m.Length;
            }

            // 한 번에 치환
            working = rule.Pattern.Replace(working, rule.Replacement);
        }

        return new ConvertedLine { Text = working, Spans = spans };
    }

    // 4) Recorded 스팬을 이용해 Paragraph 구성 (배경 + 빨간 글씨)
    private Paragraph BuildParagraphFromSpans(ConvertedLine cl)
    {
        var para = new Paragraph();

        // 변환된 토큰이 하나라도 있으면 줄 전체 배경색
        if (cl.Spans.Any())
            para.Background = Brushes.LightGoldenrodYellow;

        int pos = 0;
        foreach (var (start, len) in cl.Spans.OrderBy(s => s.Start))
        {
            // 변경 전 텍스트 부분
            if (start > pos)
                para.Inlines.Add(new Run(cl.Text.Substring(pos, start - pos)));

            // 변경된 텍스트 부분 (빨간색)
            para.Inlines.Add(new Run(cl.Text.Substring(start, len))
            {
                Foreground = Brushes.Red
            });

            pos = start + len;
        }

        // 남은 일반 텍스트
        if (pos < cl.Text.Length)
            para.Inlines.Add(new Run(cl.Text.Substring(pos)));

        return para;
    }

    // 저장 버튼 클릭 이벤트
    private void SaveButton_Click(object sender, RoutedEventArgs e)
    {
        if (JsRichTextBox.Document == null) return;

        var dlg = new Microsoft.Win32.SaveFileDialog
        {
            FileName = Path.GetFileNameWithoutExtension(_lastInputFilePath) + ".js",
            Filter   = "JavaScript 파일 (*.js)|*.js"
        };
        if (dlg.ShowDialog() != true) return;

        // RichTextBox 전체 텍스트 추출
        var text = new TextRange(
            JsRichTextBox.Document.ContentStart,
            JsRichTextBox.Document.ContentEnd
        ).Text;

        File.WriteAllText(dlg.FileName, text, Encoding.GetEncoding(932));
        MessageBox.Show("저장 완료", "완료", MessageBoxButton.OK, MessageBoxImage.Information);
    }

    // 5) 스크롤 동기화 설정
    private void SyncScroll()
    {
        var sv1 = GetScrollViewer(AsRichTextBox);
        var sv2 = GetScrollViewer(JsRichTextBox);
        if (sv1 == null || sv2 == null) return;

        // 중복 핸들러 방지
        sv1.ScrollChanged -= Left_ScrollChanged;
        sv2.ScrollChanged -= Right_ScrollChanged;
        sv1.ScrollChanged += Left_ScrollChanged;
        sv2.ScrollChanged += Right_ScrollChanged;
    }

    // 왼쪽 RichTextBox 스크롤 이벤트
    private void Left_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        if (_isSyncing) return;
        _isSyncing = true;
        var sv1 = (ScrollViewer)sender;
        var sv2 = GetScrollViewer(JsRichTextBox);
        sv2?.ScrollToVerticalOffset(sv1.VerticalOffset);
        _isSyncing = false;
    }

    // 오른쪽 RichTextBox 스크롤 이벤트
    private void Right_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        if (_isSyncing) return;
        _isSyncing = true;
        var sv2 = (ScrollViewer)sender;
        var sv1 = GetScrollViewer(AsRichTextBox);
        sv1?.ScrollToVerticalOffset(sv2.VerticalOffset);
        _isSyncing = false;
    }

    // VisualTreeHelper를 이용해 ScrollViewer 추출
    private ScrollViewer GetScrollViewer(DependencyObject depObj)
    {
        if (depObj is ScrollViewer) return (ScrollViewer)depObj;
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            var child = VisualTreeHelper.GetChild(depObj, i);
            var result = GetScrollViewer(child);
            if (result != null) return result;
        }
        return null;
    }
}

}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?